class Session(object):
    AUTH_TYPE_NONE = 0x00
    AUTH_TYPE_MD2 = 0x01
    AUTH_TYPE_MD5 = 0x02
    AUTH_TYPE_PASSWORD = 0x04
    AUTH_TYPE_OEM = 0x05

    PRIV_LEVEL_USER = 2
    PRIV_LEVEL_OPERATOR = 3
    PRIV_LEVEL_ADMINISTRATOR = 4
    PRIV_LEVEL_OEM = 5

    session_id = None
    _interface = None
    _auth_type = AUTH_TYPE_NONE
    _auth_username = None
    _auth_password = None
    _rmcp_host = None
    _rmcp_port = None
    _serial_port = None
    _serial_baudrate = None

    def __init__(self):
        self.established = False
        self.sid = 0
        self.sequence_number = 0
        self.activated = False

    def _get_interface(self):
        try:
            return self._interface
        except AttributeError:
            raise RuntimeError('No interface has been set')

    def _set_interface(self, interface):
        self._interface = interface

    def increment_sequence_number(self):
        self.sequence_number += 1
        if self.sequence_number > 0xffffffff:
            self.sequence_number = 1

    def set_session_type_rmcp(self, host, port=623):
        self._rmcp_host = host
        self._rmcp_port = port

    @property
    def rmcp_host(self):
        return self._rmcp_host

    @property
    def rmcp_port(self):
        return self._rmcp_port

    def set_session_type_serial(self, port, baudrate):
        self._serial_port = port
        self._serial_baudrate = baudrate

    @property
    def serial_port(self):
        return self._serial_port

    @property
    def serial_baudrate(self):
        return self._serial_baudrate

    def _set_auth_type(self, auth_type):
        self._auth_type = auth_type

    def _get_auth_type(self):
        return self._auth_type

    def set_auth_type_user(self, username, password):
        self._auth_type = self.AUTH_TYPE_PASSWORD
        self._auth_username = username
        self._auth_password = password

    @property
    def auth_username(self):
        return self._auth_username

    @property
    def auth_password(self):
        return self._auth_password

    def establish(self):
        if hasattr(self.interface, 'establish_session'):
            self.interface.establish_session(self)

    def close(self):
        if hasattr(self.interface, 'close_session'):
            self.interface.close_session()

    def rmcp_ping(self):
        if hasattr(self.interface, 'rmcp_ping'):
            self.interface.rmcp_ping()

    def __str__(self):
        string = 'Session:\n'
        string += '  ID: 0x%08x\n' % self.sid
        string += '  Seq: 0x%08x\n' % self.sequence_number
        string += '  Host: %s:%s\n' % (self._rmcp_host, self._rmcp_port)
        string += '  Auth.: %s\n' % self.auth_type
        string += '  User: %s\n' % self._auth_username
        string += '  Password: %s\n' % self._auth_password
        string += '\n'
        return string

    interface = property(_get_interface, _set_interface)
    auth_type = property(_get_auth_type, _set_auth_type) class IpmiTimeoutError(Exception):
    """Timeout occurred."""
    pass class IpmiConnectionError(Exception):
    """Connection error."""
    def __init__(self, msg=None):
        self.msg = msg

    def __str__(self):
        return "{}".format(self.msg) def log():
    return logging.getLogger('pyipmi') class MessageRegistry(object):
    def __init__(self):
    def register_class(self, cls):
    def create(self, netfn, cmdid, group_extension, *args, **kwargs):
    def create_response(self, req):
    def create_request_by_name(self, name, *args, **kwargs):
    def create_response_by_name(self, name, *args, **kwargs):
DEFAULT_REGISTRY = MessageRegistry() class BaseField(object):
class ByteArray(BaseField):
class VariableByteArray(ByteArray):
class UnsignedInt(BaseField):
class String(BaseField):
class CompletionCode(UnsignedInt):
class UnsignedIntMask(UnsignedInt):
class Timestamp(UnsignedInt):
class Conditional(object):
class Optional(object):
class RemainingBytes(BaseField):
class Bitfield(BaseField):
    class Bit(object):
    class ReservedBit(Bit):
    class BitWrapper(object):
class GroupExtensionIdentifier(UnsignedInt):
class Message(object):
    def __init__(self, name, length, default=None):
    def decode(self, obj, data):
    def encode(self, obj, data):
    def create(self):
    def __init__(self, name, length, default=None):
    def _length(self, obj):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
    def __init__(self, name, length_func):
    def _length(self, obj):
    def create(self):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
    def __init__(self, name='completion_code'):
    def decode(self, obj, data):
    def __init__(self, name, length, mask, default=None):
    def __init__(self, name):
    def __init__(self, cond_fn, field):
    def __getattr__(self, name):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
    def __init__(self, field):
    def __getattr__(self, name):
    def decode(self, obj, data):
    def encode(self, obj, data):
    def create(self):
    def __init__(self, name):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
        def __init__(self, name, width=1, default=None):
        def __init__(self, width, default=0):
        def __init__(self, bits, length):
        def __str__(self):
        def __int__(self):
        def _get_value(self):
        def _set_value(self, value):
    def __init__(self, name, length, *bits):
    def _precalc_offsets(self):
    def encode(self, obj, data):
    def decode(self, obj, data):
    def create(self):
    def __init__(self, name='picmg_identifier', value=None):
    def __init__(self, *args, **kwargs):
    def _set_field(self, name, value):
    def __str__(self):
    def _create_fields(self):
    def _pack(self):
    def _encode(self):
    def _decode(self, data):
    def _is_request(self):
    def _is_response(self):
    RESERVED_FIELD_NAMES = ['cmdid', 'netfn', 'lun', 'group_extension'] CC_OK = 0x00 def py3dec_unic_bytes_fix(dat):
    # python 3 unicode fix
    if _PY3:
        return dat.decode('raw_unicode_escape')
    return dat class ByteBuffer(object):
    def __init__(self, data=None):

        if data is not None:
            self.array = array('B', data)
        else:
            self.array = array('B')

    def push_unsigned_int(self, value, length):
        for i in range(length):
            self.array.append((value >> (8*i) & 0xff))

    def pop_unsigned_int(self, length):
        value = 0
        for i in range(length):
            try:
                value |= self.array.pop(0) << (8*i)
            except IndexError:
                raise DecodingError('Data too short for message')
        return value

    def push_string(self, value):
        if _PY3 and isinstance(value, str):
            # Encode Unicode to UTF-8
            value = value.encode()
        py3_array_frombytes(self.array, value)

    def pop_string(self, length):
        string = self.array[0:length]
        del self.array[0:length]
        return py3_array_tobytes(string)
        # return py3dec_unic_bytes_fix(string.tostring())

    def pop_slice(self, length):
        if len(self.array) < length:
            raise DecodingError('Data too short for message')

        c = ByteBuffer(self.array[0:length])
        self.__delslice__(0, length)
        return c

    def tobytes(self):
        return self.array.tobytes()

    def tostring(self):
        return py3_array_tobytes(self.array)

    def extend(self, data):
        self.array.extend(data)

    def append_array(self, a):
        self.array.extend(a)

    def __getslice__(self, a, b):
        return self.array[a:b]

    def __delslice__(self, a, b):
        del self.array[a:b]

    def __len__(self):
        return len(self.array)

    def __getitem__(self, idx):
        return self.array[idx] def py3_array_tobytes(msg):
    if _PY3:
        return msg.tobytes()
    else:
        return msg.tostring()
import re
from subprocess import Popen, PIPE
from array import array
from ..session import Session
from ..errors import IpmiTimeoutError, IpmiConnectionError
from ..logger import log
from ..msgs import encode_message, decode_message, create_message
from ..msgs.constants import CC_OK
from ..utils import py3dec_unic_bytes_fix, ByteBuffer, py3_array_tobytes
# Copyright (c) 2014  Kontron Europe GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA






class Ipmitool(object):
    """This interface uses the ipmitool raw command.

    This "emulates" a RMCP session by using raw commands.

    It uses the session information to assemble the correct ipmitool
    parameters. Therefore, a session has to be established before any request
    can be sent.
    """

    NAME = 'ipmitool'
    IPMITOOL_PATH = 'ipmitool'
    supported_interfaces = ['lan', 'lanplus', 'serial-terminal', 'open']

    def __init__(self, interface_type='lan'):
        if interface_type in self.supported_interfaces:
            self._interface_type = interface_type
        else:
            raise RuntimeError('interface type %s not supported' %
                               interface_type)

        self.re_completion_code = re.compile(
                r"Unable to send RAW command \(.*rsp=(0x[0-9a-f]+)\)")
        self.re_timeout = re.compile(
                r"Unable to send RAW command \(.*cmd=0x[0-9a-f]+\)")
        self.re_unable_establish = re.compile(
                r".*Unable to establish.*")

        self._session = None

    def establish_session(self, session):
        # just remember session parameters here
        self._session = session

    def rmcp_ping(self):

        if self._interface_type == 'serial-terminal':
            raise RuntimeError(
                'rcmp_ping not supported on "serial-terminal" interface')

        # for now this uses impitool..
        cmd = self.IPMITOOL_PATH
        cmd += (' -I %s' % self._interface_type)
        cmd += (' -H %s' % self._session.rmcp_host)
        cmd += (' -p %s' % self._session.rmcp_port)
        if self._session.auth_type == Session.AUTH_TYPE_NONE:
            cmd += (' -A NONE')
        elif self._session.auth_type == Session.AUTH_TYPE_PASSWORD:
            cmd += (' -U "%s"' % self._session.auth_username)
            cmd += (' -P "%s"' % self._session.auth_password)
        cmd += (' session info all')

        _, rc = self._run_ipmitool(cmd)
        if rc:
            raise IpmiTimeoutError()

    def is_ipmc_accessible(self, target):
        try:
            self.rmcp_ping()
            accessible = True
        except IpmiTimeoutError:
            accessible = False

        return accessible

    def _parse_output(self, output):
        cc, rsp = None, None
        hexstr = ''

        for line in py3dec_unic_bytes_fix(output).split('\n'):
            # Don't try to parse ipmitool error messages
            if 'failed' in line:
                continue

            # Check for timeout
            if self.re_timeout.match(line):
                raise IpmiTimeoutError()

            # Check for unable to establish session
            if self.re_unable_establish.match(line):

                raise IpmiConnectionError('ipmitool: {}'.format(line))