import asyncio
import glob
import importlib
import inspect
import logging
import os
import re

import sqlalchemy

from ralybot.event import Event
from ralybot.util import database

logger = logging.getLogger("ralybot")

def find_hooks(parent, module):
    """
    :type parent: Plugin
    :type module: object
    :rtype: (list[CommandHook], list[RegexHook], list[RawHook], list[SieveHook], List[EventHook], list[OnStartHook])
    """
    # set the loaded flag
    module._ralybot_loaded = True
    command = []
    regex = []
    raw = []
    sieve = []
    event = []
    periodic = []
    on_start = []
    type_lists = {"command": command, "regex": regex, "irc_raw": raw, "sieve": sieve, "event": event,
                  "periodic": periodic, "on_start": on_start}
    for name, func in module.__dict__.items():
        if hasattr(func, "_ralybot_hook"):
            # If it has the ralybot hook
            func_hooks = func._ralybot_hook

            for hook_type, func_hook in func_hooks.items():
                type_lists[hook_type].append(_hook_name_to_plugin[hook_type](parent, func_hook))

            # Delete the hook to free memory
            del func._ralybot_hook

    return command, regex, raw, sieve, event, periodic, on_start

def find_tables(code):
    """
    :type code: object
    :rtype: list[sqlalchemy.Table]
    """
    tables = []
    for name, obj in code.__dict__.items():
        if isinstance(obj, sqlalchemy.Table) and obj.metadata == database.metadata:
            # if it's a Table, and it's using our metadata, append it to the list
            tables.append(obj)

    return tables

class PluginManager:
    """
    PluginManager is the core of Ralybot plugin loading.

    PluginManager loads Plugins, and adds their Hooks to easy-access dicts/lists.

    Each Plugin represents a file, and loads hooks onto itself using find_hooks.

    Plugins are the lowest level of abstraction in this class. There are four different plugin types:
    - CommandPlugin is for bot commands
    - RawPlugin hooks onto irc_raw irc lines
    - RegexPlugin loads a regex parameter, and executes on irc lines which match the regex
    - SievePlugin is a catch-all sieve, which all other plugins go through before being executed.

    :type bot: ralybot.bot.Ralybot
    :type plugins: dict[str, Plugin]
    :type commands: dict[str, CommandHook]
    :type raw_triggers: dict[str, list[RawHook]]
    :type catch_all_triggers: list[RawHook]
    :type event_type_hooks: dict[ralybot.event.EventType, list[EventHook]]
    :type regex_hooks: list[(re.__Regex, RegexHook)]
    :type sieves: list[SieveHook]
    """

    def __init__(self, bot):
        """
        Creates a new PluginManager. You generally only need to do this from inside ralybot.bot.Ralybot
        :type bot: ralybot.bot.Ralybot
        """
        self.bot = bot

        self.plugins = {}
        self.commands = {}
        self.raw_triggers = {}
        self.catch_all_triggers = []
        self.event_type_hooks = {}
        self.regex_hooks = []
        self.sieves = []
        self._hook_waiting_queues = {}

    @asyncio.coroutine
    def load_all(self, plugin_dir):
        """
        Load a plugin from each *.py file in the given directory.

        Won't load any plugins listed in "disabled_plugins".

        :type plugin_dir: str
        """
        path_list = glob.iglob(os.path.join(plugin_dir, '*.py'))
        # Load plugins asynchronously :O
        yield from asyncio.gather(*[self.load_plugin(path) for path in path_list], loop=self.bot.loop)

    @asyncio.coroutine
    def load_plugin(self, path):
        """
        Loads a plugin from the given path and plugin object, then registers all hooks from that plugin.

        Won't load any plugins that are listed in the "disabled_plugins" section of the config.

        :type path: str
        """

        file_path = os.path.abspath(path)
        file_name = os.path.basename(path)
        title = os.path.splitext(file_name)[0]

        if "plugin_loading" in self.bot.config:
            pl = self.bot.config.get("plugin_loading")

            if pl.get("use_whitelist", False):
                if title not in pl.get("whitelist", []):
                    logger.info('Not loading plugin module "{}": plugin not whitelisted'.format(file_name))
                    return
            else:
                if title in pl.get("blacklist", []):
                    logger.info('Not loading plugin module "{}": plugin blacklisted'.format(file_name))
                    return

        # make sure to unload the previously loaded plugin from this path, if it was loaded.
        if file_name in self.plugins:
            yield from self.unload_plugin(file_path)

        module_name = "plugins.{}".format(title)
        try:
            plugin_module = importlib.import_module(module_name)
            # if this plugin was loaded before, reload it
            if hasattr(plugin_module, "_ralybot_loaded"):
                importlib.reload(plugin_module)
        except Exception:
            logger.exception("Error loading {}:".format(file_name))
            return

        # create the plugin
        plugin = Plugin(file_path, file_name, title, plugin_module)

        # proceed to register hooks

        # create database tables
        yield from plugin.create_tables(self.bot)

        # run on_start hooks
        for on_start_hook in plugin.run_on_start:
            success = yield from self.launch(on_start_hook, Event(bot=self.bot, hook=on_start_hook))
            if not success:
                logger.warning("Not registering hooks from plugin {}: on_start hook errored".format(plugin.title))

                # unregister databases
                plugin.unregister_tables(self.bot)
                return

        self.plugins[plugin.file_name] = plugin

        for periodic_hook in plugin.periodic:
            asyncio.async(self._start_periodic(periodic_hook))
            self._log_hook(periodic_hook)

        # register commands
        for command_hook in plugin.commands:
            for alias in command_hook.aliases:
                if alias in self.commands:
                    logger.warning(
                        "Plugin {} attempted to register command {} which was already registered by {}. "
                        "Ignoring new assignment.".format(plugin.title, alias, self.commands[alias].plugin.title))
                else:
                    self.commands[alias] = command_hook
            self._log_hook(command_hook)

        # register raw hooks
        for raw_hook in plugin.raw_hooks:
            if raw_hook.is_catch_all():
                self.catch_all_triggers.append(raw_hook)
            else:
                for trigger in raw_hook.triggers:
                    if trigger in self.raw_triggers:
                        self.raw_triggers[trigger].append(raw_hook)
                    else:
                        self.raw_triggers[trigger] = [raw_hook]
            self._log_hook(raw_hook)

        # register events
        for event_hook in plugin.events:
            for event_type in event_hook.types:
                if event_type in self.event_type_hooks:
                    self.event_type_hooks[event_type].append(event_hook)
                else:
                    self.event_type_hooks[event_type] = [event_hook]
            self._log_hook(event_hook)

        # register regexps
        for regex_hook in plugin.regexes:
            for regex_match in regex_hook.regexes:
                self.regex_hooks.append((regex_match, regex_hook))
            self._log_hook(regex_hook)

        # register sieves
        for sieve_hook in plugin.sieves:
            self.sieves.append(sieve_hook)
            self._log_hook(sieve_hook)

        # sort sieve hooks by priority
        self.sieves.sort(key=lambda x: x.priority)

        # we don't need this anymore
        del plugin.run_on_start

    @asyncio.coroutine
    def unload_plugin(self, path):
        """
        Unloads the plugin from the given path, unregistering all hooks from the plugin.

        Returns True if the plugin was unloaded, False if the plugin wasn't loaded in the first place.

        :type path: str
        :rtype: bool
        """
        file_name = os.path.basename(path)
        title = os.path.splitext(file_name)[0]
        if "disabled_plugins" in self.bot.config and title in self.bot.config['disabled_plugins']:
            # this plugin hasn't been loaded, so no need to unload it
            return False

        # make sure this plugin is actually loaded
        if not file_name in self.plugins:
            return False

        # get the loaded plugin
        plugin = self.plugins[file_name]

        # unregister commands
        for command_hook in plugin.commands:
            for alias in command_hook.aliases:
                if alias in self.commands and self.commands[alias] == command_hook:
                    # we need to make sure that there wasn't a conflict, so we don't delete another plugin's command
                    del self.commands[alias]

        # unregister raw hooks
        for raw_hook in plugin.raw_hooks:
            if raw_hook.is_catch_all():
                self.catch_all_triggers.remove(raw_hook)
            else:
                for trigger in raw_hook.triggers:
                    assert trigger in self.raw_triggers  # this can't be not true
                    self.raw_triggers[trigger].remove(raw_hook)
                    if not self.raw_triggers[trigger]:  # if that was the last hook for this trigger
                        del self.raw_triggers[trigger]

        # unregister events
        for event_hook in plugin.events:
            for event_type in event_hook.types:
                assert event_type in self.event_type_hooks  # this can't be not true
                self.event_type_hooks[event_type].remove(event_hook)
                if not self.event_type_hooks[event_type]:  # if that was the last hook for this event type
                    del self.event_type_hooks[event_type]

        # unregister regexps
        for regex_hook in plugin.regexes:
            for regex_match in regex_hook.regexes:
                self.regex_hooks.remove((regex_match, regex_hook))

        # unregister sieves
        for sieve_hook in plugin.sieves:
            self.sieves.remove(sieve_hook)

        # unregister databases
        plugin.unregister_tables(self.bot)

        # remove last reference to plugin
        del self.plugins[plugin.file_name]

        if self.bot.config.get("logging", {}).get("show_plugin_loading", True):
            logger.info("Unloaded all plugins from {}.py".format(plugin.title))

        return True

    def _log_hook(self, hook):
        """
        Logs registering a given hook

        :type hook: Hook
        """
        if self.bot.config.get("logging", {}).get("show_plugin_loading", True):
            logger.info("Loaded {}".format(hook))
            logger.debug("Loaded {}".format(repr(hook)))

    def _prepare_parameters(self, hook, event):
        """
        Prepares arguments for the given hook

        :type hook: ralybot.plugin.Hook
        :type event: ralybot.event.Event
        :rtype: list
        """
        parameters = []
        for required_arg in hook.required_args:
            if hasattr(event, required_arg):
                value = getattr(event, required_arg)
                parameters.append(value)
            else:
                logger.error("Plugin {} asked for invalid argument '{}', cancelling execution!"
                             .format(hook.description, required_arg))
                logger.debug("Valid arguments are: {} ({})".format(dir(event), event))
                return None
        return parameters

    def _execute_hook_threaded(self, hook, event):
        """
        :type hook: Hook
        :type event: ralybot.event.Event
        """
        event.prepare_threaded()

        parameters = self._prepare_parameters(hook, event)
        if parameters is None:
            return None

        try:
            return hook.function(*parameters)
        finally:
            event.close_threaded()

    @asyncio.coroutine
    def _execute_hook_sync(self, hook, event):
        """
        :type hook: Hook
        :type event: ralybot.event.Event
        """
        yield from event.prepare()

        parameters = self._prepare_parameters(hook, event)
        if parameters is None:
            return None

        try:
            return (yield from hook.function(*parameters))
        finally:
            yield from event.close()

    @asyncio.coroutine
    def _execute_hook(self, hook, event):
        """
        Runs the specific hook with the given bot and event.

        Returns False if the hook errored, True otherwise.

        :type hook: ralybot.plugin.Hook
        :type event: ralybot.event.Event
        :rtype: bool
        """
        try:
            # _internal_run_threaded and _internal_run_coroutine prepare the database, and run the hook.
            # _internal_run_* will prepare parameters and the database session, but won't do any error catching.
            if hook.threaded:
                out = yield from self.bot.loop.run_in_executor(None, self._execute_hook_threaded, hook, event)
            else:
                out = yield from self._execute_hook_sync(hook, event)
        except Exception:
            logger.exception("Error in hook {}".format(hook.description))
            return False

        if out is not None:
            if isinstance(out, (list, tuple)):
                # if there are multiple items in the response, return them on multiple lines
                event.reply(*out)
            else:
                event.reply(*str(out).split('\n'))
        return True

    @asyncio.coroutine
    def _sieve(self, sieve, event, hook):
        """
        :type sieve: ralybot.plugin.Hook
        :type event: ralybot.event.Event
        :type hook: ralybot.plugin.Hook
        :rtype: ralybot.event.Event
        """
        try:
            if sieve.threaded:
                result = yield from self.bot.loop.run_in_executor(None, sieve.function, self.bot, event, hook)
            else:
                result = yield from sieve.function(self.bot, event, hook)
        except Exception:
            logger.exception("Error running sieve {} on {}:".format(sieve.description, hook.description))
            return None
        else:
            return result

    @asyncio.coroutine
    def _start_periodic(self, hook):
        interval = hook.interval
        initial_interval = hook.initial_interval
        yield from asyncio.sleep(initial_interval)

        while True:
            event = Event(bot=self.bot, hook=hook)
            yield from self.launch(hook, event)
            yield from asyncio.sleep(interval)

    @asyncio.coroutine
    def launch(self, hook, event):
        """
        Dispatch a given event to a given hook using a given bot object.

        Returns False if the hook didn't run successfully, and True if it ran successfully.

        :type event: ralybot.event.Event | ralybot.event.CommandEvent
        :type hook: ralybot.plugin.Hook | ralybot.plugin.CommandHook
        :rtype: bool
        """

        if hook.type not in ("on_start", "periodic"):  # we don't need sieves on on_start hooks.
            for sieve in self.bot.plugin_manager.sieves:
                event = yield from self._sieve(sieve, event, hook)
                if event is None:
                    return False

        if hook.type == "command" and hook.auto_help and not event.text and hook.doc is not None:
            event.notice_doc()
            return False

        if hook.single_thread:
            # There should only be one running instance of this hook, so let's wait for the last event to be processed
            # before starting this one.

            key = (hook.plugin.title, hook.function_name)
            if key in self._hook_waiting_queues:
                queue = self._hook_waiting_queues[key]
                if queue is None:
                    # there's a hook running, but the queue hasn't been created yet, since there's only one hook


##   transports.py
##
##   Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
##
##   This program is free software; you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation; either version 2, or (at your option)
##   any later version.
##
##   This program 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 General Public License for more details.

# $Id: dispatcher.py,v 1.42 2007/05/18 23:18:36 normanr Exp $

"""
Main xmpppy mechanism. Provides library with methods to assign different handlers
to different XMPP stanzas.
Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defines time that
Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up.
"""

import simplexml,time,sys
from protocol import *
from client import PlugIn

DefaultTimeout=25
ID=0

class Dispatcher(PlugIn):
    """ Ancestor of PlugIn class. Handles XMPP stream, i.e. aware of stream headers.
        Can be plugged out/in to restart these headers (used for SASL f.e.). """
    def __init__(self):
        PlugIn.__init__(self)
        DBG_LINE='dispatcher'
        self.handlers={}
        self._expected={}
        self._defaultHandler=None
        self._pendingExceptions=[]
        self._eventHandler=None
        self._cycleHandlers=[]
        self._exported_methods=[self.Process,self.RegisterHandler,self.RegisterDefaultHandler,\
        self.RegisterEventHandler,self.UnregisterCycleHandler,self.RegisterCycleHandler,\
        self.RegisterHandlerOnce,self.UnregisterHandler,self.RegisterProtocol,\
        self.WaitForResponse,self.SendAndWaitForResponse,self.send,self.disconnect,\
        self.SendAndCallForResponse, ]

    def dumpHandlers(self):
        """ Return set of user-registered callbacks in it's internal format.
            Used within the library to carry user handlers set over Dispatcher replugins. """
        return self.handlers
    def restoreHandlers(self,handlers):
        """ Restores user-registered callbacks structure from dump previously obtained via dumpHandlers.
            Used within the library to carry user handlers set over Dispatcher replugins. """
        self.handlers=handlers

    def _init(self):
        """ Registers default namespaces/protocols/handlers. Used internally.  """
        self.RegisterNamespace('unknown')
        self.RegisterNamespace(NS_STREAMS)
        self.RegisterNamespace(self._owner.defaultNamespace)
        self.RegisterProtocol('iq',Iq)
        self.RegisterProtocol('presence',Presence)
        self.RegisterProtocol('message',Message)
        self.RegisterDefaultHandler(self.returnStanzaHandler)
        self.RegisterHandler('error',self.streamErrorHandler,xmlns=NS_STREAMS)

    def plugin(self, owner):
        """ Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally."""
        self._init()
        for method in self._old_owners_methods:
            if method.__name__=='send': self._owner_send=method; break
        self._owner.lastErrNode=None
        self._owner.lastErr=None
        self._owner.lastErrCode=None
        self.StreamInit()

    def plugout(self):
        """ Prepares instance to be destructed. """
        self.Stream.dispatch=None
        self.Stream.DEBUG=None
        self.Stream.features=None
        self.Stream.destroy()

    def StreamInit(self):
        """ Send an initial stream header. """
        self.Stream=simplexml.NodeBuilder()
        self.Stream._dispatch_depth=2
        self.Stream.dispatch=self.dispatch
        self.Stream.stream_header_received=self._check_stream_start
        self._owner.debug_flags.append(simplexml.DBG_NODEBUILDER)
        self.Stream.DEBUG=self._owner.DEBUG
        self.Stream.features=None
        self._metastream=Node('stream:stream')
        self._metastream.setNamespace(self._owner.Namespace)
        self._metastream.setAttr('version','1.0')
        self._metastream.setAttr('xmlns:stream',NS_STREAMS)
        self._metastream.setAttr('to',self._owner.Server)
        self._owner.send("<?xml version='1.0'?>%s>"%str(self._metastream)[:-2])

    def _check_stream_start(self,ns,tag,attrs):
        if ns<>NS_STREAMS or tag<>'stream':
            raise ValueError('Incorrect stream start: (%s,%s). Terminating.'%(tag,ns))

    def Process(self, timeout=0):
        """ Check incoming stream for data waiting. If "timeout" is positive - block for as max. this time.
            Returns:
            1) length of processed data if some data were processed;
            2) '0' string if no data were processed but link is alive;
            3) 0 (zero) if underlying connection is closed.
            Take note that in case of disconnection detect during Process() call
            disconnect handlers are called automatically.
        """
        for handler in self._cycleHandlers: handler(self)
        if len(self._pendingExceptions) > 0:
            _pendingException = self._pendingExceptions.pop()
            raise _pendingException[0], _pendingException[1], _pendingException[2]
        if self._owner.Connection.pending_data(timeout):
            try: data=self._owner.Connection.receive()
            except IOError: return
            self.Stream.Parse(data)
            if len(self._pendingExceptions) > 0:
                _pendingException = self._pendingExceptions.pop()
                raise _pendingException[0], _pendingException[1], _pendingException[2]
            if data: return len(data)
        return '0'      # It means that nothing is received but link is alive.

    def RegisterNamespace(self,xmlns,order='info'):
        """ Creates internal structures for newly registered namespace.
            You can register handlers for this namespace afterwards. By default one namespace
            already registered (jabber:client or jabber:component:accept depending on context. """
        self.DEBUG('Registering namespace "%s"'%xmlns,order)
        self.handlers[xmlns]={}
        self.RegisterProtocol('unknown',Protocol,xmlns=xmlns)
        self.RegisterProtocol('default',Protocol,xmlns=xmlns)

    def RegisterProtocol(self,tag_name,Proto,xmlns=None,order='info'):
        """ Used to declare some top-level stanza name to dispatcher.
           Needed to start registering handlers for such stanzas.
           Iq, message and presence protocols are registered by default. """
        if not xmlns: xmlns=self._owner.defaultNamespace
        self.DEBUG('Registering protocol "%s" as %s(%s)'%(tag_name,Proto,xmlns), order)
        self.handlers[xmlns][tag_name]={type:Proto, 'default':[]}

    def RegisterNamespaceHandler(self,xmlns,handler,typ='',ns='', makefirst=0, system=0):
        """ Register handler for processing all stanzas for specified namespace. """
        self.RegisterHandler('default', handler, typ, ns, xmlns, makefirst, system)

    def RegisterHandler(self,name,handler,typ='',ns='',xmlns=None, makefirst=0, system=0):
        """Register user callback as stanzas handler of declared type. Callback must take
           (if chained, see later) arguments: dispatcher instance (for replying), incomed
           return of previous handlers.
           The callback must raise xmpp.NodeProcessed just before return if it want preven
           callbacks to be called with the same stanza as argument _and_, more importantly
           library from returning stanza to sender with error set (to be enabled in 0.2 ve
            Arguments:
              "name" - name of stanza. F.e. "iq".
              "handler" - user callback.
              "typ" - value of stanza's "type" attribute. If not specified any value match
              "ns" - namespace of child that stanza must contain.
              "chained" - chain together output of several handlers.
              "makefirst" - insert handler in the beginning of handlers list instead of
                adding it to the end. Note that more common handlers (i.e. w/o "typ" and "
                will be called first nevertheless.
              "system" - call handler even if NodeProcessed Exception were raised already.
            """
        if not xmlns: xmlns=self._owner.defaultNamespace
        self.DEBUG('Registering handler %s for "%s" type->%s ns->%s(%s)'%(handler,name,typ,ns,xmlns), 'info')
        if not typ and not ns: typ='default'
        if not self.handlers.has_key(xmlns): self.RegisterNamespace(xmlns,'warn')
        if not self.handlers[xmlns].has_key(name): self.RegisterProtocol(name,Protocol,xmlns,'warn')
        if not self.handlers[xmlns][name].has_key(typ+ns): self.handlers[xmlns][name][typ+ns]=[]
        if makefirst: self.handlers[xmlns][name][typ+ns].insert(0,{'func':handler,'system':system})
        else: self.handlers[xmlns][name][typ+ns].append({'func':handler,'system':system})

    def RegisterHandlerOnce(self,name,handler,typ='',ns='',xmlns=None,makefirst=0, system=0):
        """ Unregister handler after first call (not implemented yet). """
        if not xmlns: xmlns=self._owner.defaultNamespace
        self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)

    def UnregisterHandler(self,name,handler,typ='',ns='',xmlns=None):
        """ Unregister handler. "typ" and "ns" must be specified exactly the same as with registering."""
        if not xmlns: xmlns=self._owner.defaultNamespace
        if not self.handlers.has_key(xmlns): return
        if not typ and not ns: typ='default'
        for pack in self.handlers[xmlns][name][typ+ns]:
            if handler==pack['func']: break
        else: pack=None
        try: self.handlers[xmlns][name][typ+ns].remove(pack)
        except ValueError: pass

    def RegisterDefaultHandler(self,handler):
        """ Specify the handler that will be used if no NodeProcessed exception were raised.
            This is returnStanzaHandler by default. """
        self._defaultHandler=handler

    def RegisterEventHandler(self,handler):
        """ Register handler that will process events. F.e. "FILERECEIVED" event. """
        self._eventHandler=handler

    def returnStanzaHandler(self,conn,stanza):
        """ Return stanza back to the sender with <feature-not-implemennted/> error set. """
        if stanza.getType() in ['get','set']:
            conn.send(Error(stanza,ERR_FEATURE_NOT_IMPLEMENTED))

    def streamErrorHandler(self,conn,error):
        name,text='error',error.getData()
        for tag in error.getChildren():
            if tag.getNamespace()==NS_XMPP_STREAMS:
                if tag.getName()=='text': text=tag.getData()
                else: name=tag.getName()
        if name in stream_exceptions.keys(): exc=stream_exceptions[name]
        else: exc=StreamError
        raise exc((name,text))

    def RegisterCycleHandler(self,handler):
        """ Register handler that will be called on every Dispatcher.Process() call. """
        if handler not in self._cycleHandlers: self._cycleHandlers.append(handler)

    def UnregisterCycleHandler(self,handler):
        """ Unregister handler that will is called on every Dispatcher.Process() call."""
        if handler in self._cycleHandlers: self._cycleHandlers.remove(handler)

    def Event(self,realm,event,data):
        """ Raise some event. Takes three arguments:
            1) "realm" - scope of event. Usually a namespace.
            2) "event" - the event itself. F.e. "SUCESSFULL SEND".
            3) data that comes along with event. Depends on event."""
        if self._eventHandler: self._eventHandler(realm,event,data)

    def dispatch(self,stanza,session=None,direct=0):
        """ Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it.
            Called internally. """
        if not session: session=self
        session.Stream._mini_dom=None
        name=stanza.getName()

        if not direct and self._owner._route:
            if name == 'route':
                if stanza.getAttr('error') == None:
                    if len(stanza.getChildren()) == 1:
                        stanza = stanza.getChildren()[0]
                        name=stanza.getName()
                    else:
                        for each in stanza.getChildren():
                            self.dispatch(each,session,direct=1)
                        return
            elif name == 'presence':
                return
            elif name in ('features','bind'):
                pass
            else:
                raise UnsupportedStanzaType(name)

        if name=='features': session.Stream.features=stanza

        xmlns=stanza.getNamespace()
        if not self.handlers.has_key(xmlns):
            self.DEBUG("Unknown namespace: " + xmlns,'warn')
            xmlns='unknown'
        if not self.handlers[xmlns].has_key(name):
            self.DEBUG("Unknown stanza: " + name,'warn')
            name='unknown'
        else:
            self.DEBUG("Got %s/%s stanza"%(xmlns,name), 'ok')

        if stanza.__class__.__name__=='Node': stanza=self.handlers[xmlns][name][type](node=stanza)

        typ=stanza.getType()
        if not typ: typ=''
        stanza.props=stanza.getProperties()
        ID=stanza.getID()

        session.DEBUG("Dispatching %s stanza with type->%s props->%s id->%s"%(name,typ,stanza.props,ID),'ok')

        list=['default']                                                     # we will use all handlers:
        if self.handlers[xmlns][name].has_key(typ): list.append(typ)                # from very common...
        for prop in stanza.props:
            if self.handlers[xmlns][name].has_key(prop): list.append(prop)
            if typ and self.handlers[xmlns][name].has_key(typ+prop): list.append(typ+prop)  # ...to very particular

        chain=self.handlers[xmlns]['default']['default']
        for key in list:
            if key: chain = chain + self.handlers[xmlns][name][key]

        output=''
        if session._expected.has_key(ID):
            user=0
            if type(session._expected[ID])==type(()):
                cb,args=session._expected[ID]
                session.DEBUG("Expected stanza arrived. Callback %s(%s) found!"%(cb,args),'ok')
                try: cb(session,stanza,**args)
                except Exception, typ:
                    if typ.__class__.__name__<>'NodeProcessed': raise
            else:
                session.DEBUG("Expected stanza arrived!",'ok')
                session._expected[ID]=stanza
        else: user=1
        for handler in chain:


##############################################################################
#
# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Functional tests for File and Image.

$Id: ftests.py 25177 2004-06-02 13:17:31Z jim $
"""
import unittest
from xml.sax.saxutils import escape
from StringIO import StringIO

from zope.app.testing.functional import BrowserTestCase
from zope.app.file.file import File
from zope.app.file.image import Image
from zope.app.file.tests.test_image import zptlogo

class FileTest(BrowserTestCase):

    content = u'File <Data>'

    def addFile(self):
        file = File(self.content)
        root = self.getRootFolder()
        root['file'] = file
        self.commit()

    def testAddForm(self):
        response = self.publish(
            '/+/zope.app.file.File=',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Add a File' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_('Object Name' in body)
        self.assert_('"Add"' in body)
        self.checkForBrokenLinks(body, '/+/zope.app.file.File=',
                                 'mgr:mgrpw')

    def testAdd(self):
        response = self.publish(
            '/+/zope.app.file.File=',
            form={'type_name': u'zope.app.file.File',
                  'field.data': StringIO('A file'),
                  'field.data.used': '',
                  'add_input_name': u'file',
                  'UPDATE_SUBMIT': u'Add'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 302)
        self.assertEqual(response.getHeader('Location'),
                         'http://localhost/@@contents.html')
        root = self.getRootFolder()
        self.assert_('file' in root)
        file = root['file']
        self.assertEqual(file.data, 'A file')

    def testAddWithoutName(self):
        data = StringIO('File Contents')
        data.filename="test.txt"
        response = self.publish(
            '/+/zope.app.file.File=',
            form={'type_name': u'zope.app.file.File',
                  'field.data': data,
                  'field.data.used': '',
                  'UPDATE_SUBMIT': u'Add'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 302)
        self.assertEqual(response.getHeader('Location'),
                         'http://localhost/@@contents.html')
        root = self.getRootFolder()
        self.assert_('test.txt' in root)
        file = root['test.txt']
        self.assertEqual(file.data, 'File Contents')

    def testEditForm(self):
        self.addFile()
        response = self.publish(
            '/file/@@edit.html',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Change a file' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_(escape(self.content) in body)
        self.checkForBrokenLinks(body, '/file/@@edit.html', 'mgr:mgrpw')

    def testEdit(self):
        self.addFile()
        response = self.publish(
            '/file/@@edit.html',
            form={'field.data': u'
A File
',
                  'field.data.used': '',
                  'field.contentType': u'text/plain',
                  'UPDATE_SUBMIT': u'Edit'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Change a file' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_(escape(u'
A File
') in body)
        root = self.getRootFolder()
        file = root['file']
        self.assertEqual(file.data, '
A File
')
        self.assertEqual(file.contentType, 'text/plain')

    def testUploadForm(self):
        self.addFile()
        response = self.publish(
            '/file/@@upload.html',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Upload a file' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.failIf(escape(self.content) in body)
        self.checkForBrokenLinks(body, '/file/@@upload.html', 'mgr:mgrpw')

    def testUpload(self):
        self.addFile()
        response = self.publish(
            '/file/@@upload.html',
            form={'field.data': StringIO('
A file
'),
                  'field.data.used': '',
                  'field.contentType': u'text/plain',
                  'UPDATE_SUBMIT': u'Change'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Upload a file' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.failIf(escape(u'
A File
') in body)
        root = self.getRootFolder()
        file = root['file']
        self.assertEqual(file.data, '
A file
')
        self.assertEqual(file.contentType, 'text/plain')

    def testIndex(self):
        self.addFile()
        response = self.publish(
            '/file/@@index.html',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assertEqual(body, self.content)
        self.checkForBrokenLinks(body, '/file/@@index.html', 'mgr:mgrpw')

    def testPreview(self):
        self.addFile()
        response = self.publish(
            '/file/@@preview.html',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('<iframe src="."' in body)
        self.checkForBrokenLinks(body, '/file/@@preview.html', 'mgr:mgrpw')

class ImageTest(BrowserTestCase):

    content = zptlogo

    def addImage(self):
        image = Image(self.content)
        root = self.getRootFolder()
        root['image'] = image
        self.commit()

    def testAddForm(self):
        response = self.publish(
            '/+/zope.app.file.Image=',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Add an Image' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_('Object Name' in body)
        self.assert_('"Add"' in body)
        self.checkForBrokenLinks(body, '/+/zope.app.file.Image=',
                                 'mgr:mgrpw')

    def testAdd(self):
        response = self.publish(
            '/+/zope.app.file.Image=',
            form={'type_name': u'zope.app.image.Image',
                  'field.data': StringIO(self.content),
                  'field.data.used': '',
                  'add_input_name': u'image',
                  'UPDATE_SUBMIT': u'Add'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 302)
        self.assertEqual(response.getHeader('Location'),
                         'http://localhost/@@contents.html')
        root = self.getRootFolder()
        self.assert_('image' in root)
        image = root['image']
        self.assertEqual(image.data, self.content)

    def testAddWithoutName(self):
        data = StringIO(self.content)
        data.filename="test.gif"
        response = self.publish(
            '/+/zope.app.file.Image=',
            form={'type_name': u'zope.app.image.Image',
                  'field.data': data,
                  'field.data.used': '',
                  'UPDATE_SUBMIT': u'Add'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 302)
        self.assertEqual(response.getHeader('Location'),
                         'http://localhost/@@contents.html')
        root = self.getRootFolder()
        self.assert_('test.gif' in root)
        image = root['test.gif']
        self.assertEqual(image.data, self.content)

    def testUploadForm(self):
        self.addImage()
        response = self.publish(
            '/image/@@upload.html',
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Upload an image' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_('1 KB 16x16' in body)
        self.checkForBrokenLinks(body, '/image/@@upload.html', 'mgr:mgrpw')

    def testUpload(self):
        self.addImage()
        response = self.publish(
            '/image/@@upload.html',
            form={'field.data': StringIO(''),
                  'field.data.used': '',
                  'UPDATE_SUBMIT': u'Change'},
            basic='mgr:mgrpw')
        self.assertEqual(response.getStatus(), 200)
        body = response.getBody()
        self.assert_('Upload an image' in body)
        self.assert_('Content Type' in body)
        self.assert_('Data' in body)
        self.assert_('0 KB ?x?' in body)
        root = self.getRootFolder()


#!/usr/bin/python
# (c) 2018, NetApp, Inc
# GNU General Public License v3.0+ (see COPYING or
# https://www.gnu.org/licenses/gpl-3.0.txt)

'''
Element OS Software Snapshot Manager
'''
from __future__ import absolute_import, division, print_function
__metaclass__ = type

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = '''

module: na_elementsw_snapshot

short_description: NetApp Element Software Manage Snapshots
extends_documentation_fragment:
    - netapp.solidfire
version_added: '2.7'
author: NetApp Ansible Team (ng-ansibleteam@netapp.com)
description:
    - Create, Modify or Delete Snapshot on Element OS Cluster.

options:
    name:
        description:
        - Name of new snapshot create.
        - If unspecified, date and time when the snapshot was taken is used.

    state:
        description:
        - Whether the specified snapshot should exist or not.
        choices: ['present', 'absent']
        default: 'present'

    src_volume_id:
        description:
        - ID or Name of active volume.
        required: true

    account_id:
        description:
        - Account ID or Name of Parent/Source Volume.
        required: true

    retention:
        description:
        - Retention period for the snapshot.
        - Format is 'HH:mm:ss'.

    src_snapshot_id:
        description:
        - ID or Name of an existing snapshot.
        - Required when C(state=present), to modify snapshot properties.
        - Required when C(state=present), to create snapshot from another snapshot in the volume.
        - Required when C(state=absent), to delete snapshot.

    enable_remote_replication:
        description:
        - Flag, whether to replicate the snapshot created to a remote replication cluster.
        - To enable specify 'true' value.
        type: bool

    snap_mirror_label:
        description:
        - Label used by SnapMirror software to specify snapshot retention policy on SnapMirror endpoint.

    expiration_time:
        description:
        - The date and time (format ISO 8601 date string) at which this snapshot will expire.

    password:
        description:
        - Element OS access account password
        aliases:
        - pass

    username:
        description:
        - Element OS access account user-name
        aliases:
        - user

'''

EXAMPLES = """
   - name: Create snapshot
     tags:
     - elementsw_create_snapshot
     na_elementsw_snapshot:
       hostname: "{{ elementsw_hostname }}"
       username: "{{ elementsw_username }}"
       password: "{{ elementsw_password }}"
       state: present
       src_volume_id: 118
       account_id: sagarsh
       name: newsnapshot-1

   - name: Modify Snapshot
     tags:
     - elementsw_modify_snapshot
     na_elementsw_snapshot:
       hostname: "{{ elementsw_hostname }}"
       username: "{{ elementsw_username }}"
       password: "{{ elementsw_password }}"
       state: present
       src_volume_id: sagarshansivolume
       src_snapshot_id: test1
       account_id: sagarsh
       expiration_time: '2018-06-16T12:24:56Z'
       enable_remote_replication: false

   - name: Delete Snapshot
     tags:
     - elementsw_delete_snapshot
     na_elementsw_snapshot:
       hostname: "{{ elementsw_hostname }}"
       username: "{{ elementsw_username }}"
       password: "{{ elementsw_password }}"
       state: absent
       src_snapshot_id: deltest1
       account_id: sagarsh
       src_volume_id: sagarshansivolume
"""

RETURN = """

msg:
    description: Success message
    returned: success
    type: string

"""
import traceback

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
from ansible.module_utils.netapp_elementsw_module import NaElementSWModule

HAS_SF_SDK = netapp_utils.has_sf_sdk()

class ElementOSSnapshot(object):
    """
    Element OS Snapshot Manager
    """

    def __init__(self):
        self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
        self.argument_spec.update(dict(
            state=dict(required=False, choices=['present', 'absent'], default='present'),
            account_id=dict(required=True, type='str'),
            name=dict(required=False, type='str'),
            src_volume_id=dict(required=True, type='str'),
            retention=dict(required=False, type='str'),
            src_snapshot_id=dict(required=False, type='str'),
            enable_remote_replication=dict(required=False, type='bool'),
            expiration_time=dict(required=False, type='str'),
            snap_mirror_label=dict(required=False, type='str')
        ))

        self.module = AnsibleModule(
            argument_spec=self.argument_spec,
            supports_check_mode=True
        )

        input_params = self.module.params

        self.state = input_params['state']
        self.name = input_params['name']
        self.account_id = input_params['account_id']
        self.src_volume_id = input_params['src_volume_id']
        self.src_snapshot_id = input_params['src_snapshot_id']
        self.retention = input_params['retention']
        self.properties_provided = False

        self.expiration_time = input_params['expiration_time']
        if input_params['expiration_time'] is not None:
            self.properties_provided = True

        self.enable_remote_replication = input_params['enable_remote_replication']
        if input_params['enable_remote_replication'] is not None:
            self.properties_provided = True

        self.snap_mirror_label = input_params['snap_mirror_label']
        if input_params['snap_mirror_label'] is not None:
            self.properties_provided = True

        if self.state == 'absent' and self.src_snapshot_id is None:
            self.module.fail_json(
                msg="Please provide required parameter : snapshot_id")

        if HAS_SF_SDK is False:
            self.module.fail_json(
                msg="Unable to import the SolidFire Python SDK")
        else:
            self.sfe = netapp_utils.create_sf_connection(module=self.module)

        self.elementsw_helper = NaElementSWModule(self.sfe)

        # add telemetry attributes
        self.attributes = self.elementsw_helper.set_element_attributes(source='na_elementsw_snapshot')

    def get_account_id(self):
        """
            Return account id if found
        """
        try:
            # Update and return self.account_id
            self.account_id = self.elementsw_helper.account_exists(self.account_id)
            return self.account_id
        except Exception as err:
            self.module.fail_json(msg="Error: account_id %s does not exist" % self.account_id, exception=to_native(err))

    def get_src_volume_id(self):
        """
            Return volume id if found
        """
        src_vol_id = self.elementsw_helper.volume_exists(self.src_volume_id, self.account_id)
        if src_vol_id is not None:
            # Update and return self.volume_id
            self.src_volume_id = src_vol_id
            # Return src_volume_id
            return self.src_volume_id
        return None

    def get_snapshot(self, name=None):
        """
            Return snapshot details if found
        """
        src_snapshot = None
        if name is not None:
            src_snapshot = self.elementsw_helper.get_snapshot(name, self.src_volume_id)
        elif self.src_snapshot_id is not None:
            src_snapshot = self.elementsw_helper.get_snapshot(self.src_snapshot_id, self.src_volume_id)
        if src_snapshot is not None:
            # Update self.src_snapshot_id
            self.src_snapshot_id = src_snapshot.snapshot_id
        # Return src_snapshot
        return src_snapshot

    def create_snapshot(self):
        """
        Create Snapshot
        """
        try:
            self.sfe.create_snapshot(volume_id=self.src_volume_id,
                                     snapshot_id=self.src_snapshot_id,
                                     name=self.name,
                                     enable_remote_replication=self.enable_remote_replication,
                                     retention=self.retention,
                                     snap_mirror_label=self.snap_mirror_label,
                                     attributes=self.attributes)
        except Exception as exception_object:
            self.module.fail_json(
                msg='Error creating snapshot %s' % (
                    to_native(exception_object)),
                exception=traceback.format_exc())

    def modify_snapshot(self):
        """
        Modify Snapshot Properties
        """
        try:
            self.sfe.modify_snapshot(snapshot_id=self.src_snapshot_id,
                                     expiration_time=self.expiration_time,
                                     enable_remote_replication=self.enable_remote_replication,
                                     snap_mirror_label=self.snap_mirror_label)
        except Exception as exception_object:
            self.module.fail_json(
                msg='Error modify snapshot %s' % (
                    to_native(exception_object)),
                exception=traceback.format_exc())

    def delete_snapshot(self):
        """
        Delete Snapshot
        """
        try:
            self.sfe.delete_snapshot(snapshot_id=self.src_snapshot_id)
        except Exception as exception_object:
            self.module.fail_json(
                msg='Error delete snapshot %s' % (
                    to_native(exception_object)),
                exception=traceback.format_exc())

    def apply(self):
        """
        Check, process and initiate snapshot operation
        """
        changed = False
        snapshot_delete = False
        snapshot_create = False
        snapshot_modify = False
        result_message = None
        self.get_account_id()

        # Dont proceed if source volume is not found
        if self.get_src_volume_id() is None:
            self.module.fail_json(msg="Volume id not found %s" % self.src_volume_id)

        # Get snapshot details using source volume
        snapshot_detail = self.get_snapshot()

        if snapshot_detail:
            if self.properties_provided:
                if self.expiration_time != snapshot_detail.expiration_time:
                    changed = True
                else:   # To preserve value in case  parameter expiration_time is not defined/provided.
                    self.expiration_time = snapshot_detail.expiration_time

                if self.enable_remote_replication != snapshot_detail.enable_remote_replication:
                    changed = True
                else:   # To preserve value in case  parameter enable_remote_Replication is not defined/provided.
                    self.enable_remote_replication = snapshot_detail.enable_remote_replication

                if self.snap_mirror_label != snapshot_detail.snap_mirror_label:
                    changed = True
                else:   # To preserve value in case  parameter snap_mirror_label is not defined/provided.
                    self.snap_mirror_label = snapshot_detail.snap_mirror_label

        if self.account_id is None or self.src_volume_id is None or self.module.check_mode:
            changed = False
            result_message = "Check mode, skipping changes"
        elif self.state == 'absent' and snapshot_detail is not None:
            self.delete_snapshot()
            changed = True
        elif self.state == 'present' and snapshot_detail is not None:
            if changed:
                self.modify_snapshot()   # Modify Snapshot properties
            elif not self.properties_provided:
                if self.name is not None:
                    snapshot = self.get_snapshot(self.name)
                    # If snapshot with name already exists return without performing any action
                    if snapshot is None:
                        self.create_snapshot()  # Create Snapshot using parent src_snapshot_id
                        changed = True
                else:
                    self.create_snapshot()
                    changed = True


#!/usr/bin/env python

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
#       Thanks for opting for GUI version of AirCrack set of tools. This project is in early stage and require your support.             #
#       Project is based on Aircrack-ng set of tools and is specially designed to run on KALI LINUX.                                     #
#                                                                                #
#              Designed by : Hitesh Choudhary                                                                                #
#              Home page   : www.HiteshChoudhary.com                                                                                #
#              Email       : hitesh@hiteshchoudhary.com                                                                                #
#              Based on    : www.Aircrack-ng.org                                                                                #
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#

from Canvas import Line
from Tkinter import *
from Tkinter import Frame, PhotoImage, Text, Label, Button
from distutils.cmd import Command
import subprocess
import commands
from textwrap import fill
from tkFont import Font
import tkFont
import tkMessageBox
from ttk import Notebook
import pcapy
import sys
import tkFileDialog

class Feedback:

    def __init__(self, master):

	self.fname=""
        #global variables
        self.t1=StringVar()
        self.t2=StringVar()
        self.t3=StringVar()
        self.t4=StringVar()
        self.t5=StringVar()
        self.t6=StringVar()
        self.t7=StringVar()
        self.t8=StringVar()
        self.t9=StringVar()
        self.t10=StringVar()
        self.t11=StringVar()
        self.t12=StringVar()
        self.t13=StringVar()
        self.t14=StringVar()
        self.t15=StringVar()
        self.t16=StringVar()
        self.t17=StringVar()
        self.t18=StringVar()
        self.t19=StringVar()
        self.t20=StringVar()
        self.t21=StringVar()
        self.t22=StringVar()
        self.t23=StringVar()
        self.t24=StringVar()
        self.t25=StringVar()
        self.t26=StringVar()
        self.t27=StringVar()

        self.var1=StringVar()
        self.var2=StringVar()
        self.var3=StringVar()
        self.var4=StringVar()
        self.var5=StringVar()
        self.var6=StringVar()
        self.var7=StringVar()
        self.var8=StringVar()
        self.var9=StringVar()
        self.var10=StringVar()
        self.var11=StringVar()
        self.var12=StringVar()
        self.var13=StringVar()
        self.var14=StringVar()
        self.var15=StringVar()
        self.var16=StringVar()
        self.var17=StringVar()
        self.var18=StringVar()
        self.var19=StringVar()
        self.var20=StringVar()
        self.var21=StringVar()
        self.var22=StringVar()
        self.var23=StringVar()
        self.var24=StringVar()
        self.var25=StringVar()
        self.var26=StringVar()
        self.var27=StringVar()
        #end

        mymaster = Frame(master, name='mymaster') # create Frame in "root"
        mymaster.pack(fill=BOTH)
        #min and max size of window
        #master.minsize(width=900, height=900)
        #master.maxsize(width=650, height=500)
        #end

        #title of window
        master.title("Aireplay-ng")
        #end

        #for the style of fonts
        self.customFont = tkFont.Font(family="Helvetica", size=12)
        self.myfont = tkFont.Font(family="Helvetica", size=10)
        self.myfont2 = tkFont.Font(family="Helvetica", size=8)
        self.headerfont=tkFont.Font(family="Helvetica", size=15,underline = True)
        self.myfontnew=tkFont.Font(family="Helvetica", size=11,underline = True)
        #end

        nb = Notebook(mymaster, name='nb') # create Notebook in "master"
        nb.pack(fill=BOTH, padx=2, pady=3) # fill "master" but pad sides
        #content frame
        self.frame_content = Frame(nb,name="frame_content", bg="white")
        self.frame_content.pack(fill=BOTH, side=TOP, expand=True)
        nb.add(self.frame_content, text="Filter-1") # add tab to Notebook

        # repeat for each tab
        self.frame_content2 = Frame(nb, name='frame_content2', bg="white")
        nb.add(self.frame_content2, text="Filter-2")
        self.frame_content3 = Frame(nb, name='frame_content3', bg="white")
        nb.add(self.frame_content3, text="Filter-3")

        self.frame_content7 = Frame(nb, name='frame_content7', bg="white")
        nb.add(self.frame_content7, text="Detect Devices")
        self.frame_content5 = Frame(nb, name='frame_content5', bg="white")
        nb.add(self.frame_content5, text="output")

        #End

	#frame content 7
	Label(self.frame_content7, text = 'Aireplay-ng',font=self.headerfont, bg="white", padx=10, pady=10).grid(row = 0, column = 0)
        btndetect=Button(self.frame_content7, text = 'Detect', command =self.canvas_detect, height=2, width=15, font=self.customFont).grid(row = 1, column = 0, padx = 5, pady = 5)

	btndbrowse=Button(self.frame_content7, text = 'Attach File', command =self.browse_file, height=2, width=15, font=self.customFont).grid(row = 3, column = 0, padx = 5, pady = 5)
	self.lilnew1=Listbox(self.frame_content7,bg="black", fg="white", font=self.myfont, selectmode=SINGLE, width=30, height=15)
        self.lilnew1.grid(row = 1, column = 1, rowspan=3)
	#End

        Label(self.frame_content, text = 'Aireplay-ng',font=self.headerfont, bg="white", padx=10, pady=10).grid(row = 0, column = 0)
        Label(self.frame_content, text = 'Filter Options :',font=self.myfontnew, bg="white").grid(row = 1, column = 1)

        Label(self.frame_content5, text = 'Edit Command From Here',font=self.myfontnew, bg="white", justify=LEFT).grid(row = 0, column = 0)
        TextCommandBox=Text(self.frame_content5, height=5, width=30)
        TextCommandBox.grid(row=1, column=0, padx=5, pady=5)
        self.output=Text(self.frame_content5,bg="black", fg="white", font=self.myfont, height=20, width=42)
        self.output.grid(row = 0, column = 1, padx=50, pady=5, rowspan=3)
        btnsubmit=Button(self.frame_content5, width=15, height=2, text="Get Result", command=self.mycallback)
        btnsubmit.grid(row=2, column=0)
        btnclear=Button(self.frame_content5, width=15, height=2, text="Clear Output", command=self.clearoutput)
        btnclear.grid(row=3, column=0)
        #end
        self.C1 = Checkbutton(self.frame_content, text = "-b", \
                 onvalue = "-b", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var1)
        self.C1.grid(row = 2, column = 0, padx = 5, pady = 5)
        self.t1=Text(self.frame_content,height=1,width = 20)
        self.t1.grid(row = 2, column = 1, padx = 5, pady = 5)
        l1=Label(self.frame_content, text = ': MAC address, Access Point',font=self.myfont, bg="white", justify=LEFT).grid(row = 2, column = 2, padx = 5, pady = 5)

        self.C2 = Checkbutton(self.frame_content, text = "-d", \
                 onvalue = "-d", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var2)
        self.C2.grid(row = 3, column = 0, padx = 5, pady = 5)
        self.t2=Text(self.frame_content,height=1,width = 20)
        self.t2.grid(row = 3, column = 1, padx = 5, pady = 5)
        l2=Label(self.frame_content, text = ': MAC address, Destination',font=self.myfont, bg="white", justify=LEFT).grid(row = 3, column = 2, padx = 5, pady = 5)

        self.C3 = Checkbutton(self.frame_content, text = "-s", \
                 onvalue = "-s", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var3)
        self.C3.grid(row = 4, column = 0, padx = 5, pady = 5)
        self.t3=Text(self.frame_content,height=1,width = 20)
        self.t3.grid(row = 4, column = 1, padx = 5, pady = 5)
        l3=Label(self.frame_content, text = ': MAC address, Source',font=self.myfont, bg="white", justify=LEFT).grid(row = 4, column = 2, padx = 5, pady = 5)

        self.C4 = Checkbutton(self.frame_content, text = "-m", \
                 onvalue = "-m", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var4)
        self.C4.grid(row = 5, column = 0, padx = 5, pady = 5)
        self.t4=Text(self.frame_content,height=1,width = 20)
        self.t4.grid(row = 5, column = 1, padx = 5, pady = 5)
        l4=Label(self.frame_content, text = ': minimum packet length',font=self.myfont, bg="white", justify=LEFT).grid(row = 5, column = 2, padx = 5, pady = 5)

        self.C5 = Checkbutton(self.frame_content, text = "-n", \
                 onvalue = "-n", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var5)
        self.C5.grid(row = 6, column = 0, padx = 5, pady = 5)
        self.t5=Text(self.frame_content,height=1,width = 20)
        self.t5.grid(row = 6, column = 1, padx = 5, pady = 5)
        l5=Label(self.frame_content, text = ': maximum packet length',font=self.myfont, bg="white", justify=LEFT).grid(row = 6, column = 2, padx = 5, pady = 5)

        self.C6 = Checkbutton(self.frame_content, text = "-u", \
                 onvalue = "-u", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var6)
        self.C6.grid(row = 7, column = 0, padx = 5, pady = 5)
        self.t6=Text(self.frame_content,height=1,width = 20)
        self.t6.grid(row = 7, column = 1, padx = 5, pady = 5)
        l6=Label(self.frame_content, text = ': frame control, type field',font=self.myfont, bg="white", justify=LEFT).grid(row = 7, column = 2, padx = 5, pady = 5)

        self.C7 = Checkbutton(self.frame_content, text = "-v", \
                 onvalue = "-v", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var7)
        self.C7.grid(row = 8, column = 0, padx = 5, pady = 5)
        self.t7=Text(self.frame_content,height=1,width = 20)
        self.t7.grid(row = 8, column = 1, padx = 5, pady = 5)
        l7=Label(self.frame_content, text = ': frame control, subtype field',font=self.myfont, bg="white", justify=LEFT).grid(row = 8, column = 2, padx = 5, pady = 5)

        self.C8 = Checkbutton(self.frame_content, text = "-t", \
                 onvalue = "-t", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var8)
        self.C8.grid(row = 9, column = 0, padx = 5, pady = 5)
        self.t8=Text(self.frame_content,height=1,width = 20)
        self.t8.grid(row = 9, column = 1, padx = 5, pady = 5)
        l8=Label(self.frame_content, text = ':  frame control, To DS bit',font=self.myfont, bg="white", justify=LEFT).grid(row = 9, column = 2, padx = 5, pady = 5)

        self.C9 = Checkbutton(self.frame_content, text = "-r", \
                 onvalue = "-r", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var9)
        self.C9.grid(row = 10, column = 0, padx = 5, pady = 5)
        self.t9=Text(self.frame_content,height=1,width = 20)
        self.t9.grid(row = 10, column = 1, padx = 5, pady = 5)
        l9=Label(self.frame_content, text = ': frame control, From DS bit',font=self.myfont, bg="white", justify=LEFT).grid(row = 10, column = 2, padx = 5, pady = 5)

        self.C10 = Checkbutton(self.frame_content, text = "-w", \
                 onvalue = "-w", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var10)
        self.C10.grid(row = 11, column = 0, padx = 5, pady = 5)
        self.t10=Text(self.frame_content,height=1,width = 20)
        self.t10.grid(row = 11, column = 1, padx = 5, pady = 5)
        l10=Label(self.frame_content, text = ': frame control, WEP bit',font=self.myfont, bg="white", justify=LEFT).grid(row = 11, column = 2, padx = 5, pady = 5)

        Label(self.frame_content2, text = 'Aireplay-ng',font=self.headerfont, bg="white", padx=10, pady=10).grid(row = 0, column = 0)

        #frame content 2
        self.C11 = Checkbutton(self.frame_content2, text = "-x", \
                 onvalue = "-x", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var11)
        self.C11.grid(row = 12, column = 0, padx = 5, pady = 5)
        self.t11=Text(self.frame_content2,height=1,width = 20)
        self.t11.grid(row = 12, column = 1, padx = 5, pady = 5)
        l11=Label(self.frame_content2, text = ': number of packets per second',font=self.myfont, bg="white", justify=LEFT).grid(row = 12, column = 2, padx = 5, pady = 5)

        self.C12 = Checkbutton(self.frame_content2, text = "-p", \
                 onvalue = "-p", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var12)
        self.C12.grid(row = 13, column = 0, padx = 5, pady = 5)
        self.t12=Text(self.frame_content2,height=1,width = 20)
        self.t12.grid(row = 13, column = 1, padx = 5, pady = 5)
        l12=Label(self.frame_content2, text = ': set frame control word (hex)',font=self.myfont, bg="white", justify=LEFT).grid(row = 13, column = 2, padx = 5, pady = 5)

        self.C13 = Checkbutton(self.frame_content2, text = "-a", \
                 onvalue = "-a", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var13)
        self.C13.grid(row = 14, column = 0, padx = 5, pady = 5)
        self.t13=Text(self.frame_content2,height=1,width = 20)
        self.t13.grid(row = 14, column = 1, padx = 5, pady = 5)
        l13=Label(self.frame_content2, text = ': set Access Point MAC address',font=self.myfont, bg="white", justify=LEFT).grid(row = 14, column = 2, padx = 5, pady = 5)

        self.C14 = Checkbutton(self.frame_content2, text = "-c", \
                 onvalue = "-c", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var14)
        self.C14.grid(row = 15, column = 0, padx = 5, pady = 5)
        self.t14=Text(self.frame_content2,height=1,width = 20)
        self.t14.grid(row = 15, column = 1, padx = 5, pady = 5)
        l14=Label(self.frame_content2, text = ':  set Destination MAC address',font=self.myfont, bg="white", justify=LEFT).grid(row = 15, column = 2, padx = 5, pady = 5)

        self.C15 = Checkbutton(self.frame_content2, text = "-h", \
                 onvalue = "-h", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var15)
        self.C15.grid(row = 16, column = 0, padx = 5, pady = 5)
        self.t15=Text(self.frame_content2,height=1,width = 20)
        self.t15.grid(row = 16, column = 1, padx = 5, pady = 5)
        l15=Label(self.frame_content2, text = ': set Source MAC address',font=self.myfont, bg="white").grid(row = 16, column = 2, padx = 5, pady = 5)

        self.C16 = Checkbutton(self.frame_content2, text = "-e", \
                 onvalue = "-e", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var16)
        self.C16.grid(row = 17, column = 0, padx = 5, pady = 5)
        self.t16=Text(self.frame_content2,height=1,width = 20)
        self.t16.grid(row = 17, column = 1, padx = 5, pady = 5)
        l16=Label(self.frame_content2, text = ':  For fakeauth attack or injection test,',font=self.myfont, bg="white").grid(row = 17, column = 2, padx = 5, pady = 5)

        self.C17 = Checkbutton(self.frame_content2, text = "-j", \
                 onvalue = "-j", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var17)
        self.C17.grid(row = 18, column = 0, padx = 5, pady = 5)
        self.t17=Text(self.frame_content2,height=1,width = 20)
        self.t17.grid(row = 18, column = 1, padx = 5, pady = 5)
        l17=Label(self.frame_content2, text = ': arpreplay attack : inject FromDS pkts',font=self.myfont, bg="white").grid(row = 18, column = 2, padx = 5, pady = 5)

        self.C18 = Checkbutton(self.frame_content2, text = "-g", \
                 onvalue = "-g", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var18)
        self.C18.grid(row = 19, column = 0, padx = 5, pady = 5)
        self.t18=Text(self.frame_content2,height=1,width = 20)
        self.t18.grid(row = 19, column = 1, padx = 5, pady = 5)
        l18=Label(self.frame_content2, text = ': change ring buffer size (default: 8)',font=self.myfont, bg="white").grid(row = 19, column = 2, padx = 5, pady = 5)

        self.C19 = Checkbutton(self.frame_content2, text = "-k", \
                 onvalue = "-k", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var19)
        self.C19.grid(row = 20, column = 0, padx = 5, pady = 5)
        self.t19=Text(self.frame_content2,height=1,width = 20)
        self.t19.grid(row = 20, column = 1, padx = 5, pady = 5)
        l19=Label(self.frame_content2, text = ': set destination IP in fragments',font=self.myfont, bg="white").grid(row = 20, column = 2, padx = 5, pady = 5)

        self.C20 = Checkbutton(self.frame_content2, text = "-I", \
                 onvalue = "-I", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var20)
        self.C20.grid(row = 21, column = 0, padx = 5, pady = 5)
        self.t20=Text(self.frame_content2,height=1,width = 20)
        self.t20.grid(row = 21, column = 1, padx = 5, pady = 5)
        l20=Label(self.frame_content2, text = ': set source IP in fragments',font=self.myfont, bg="white").grid(row = 21, column = 2, padx = 5, pady = 5)
        #frame content 3
        Label(self.frame_content3, text = 'Aireplay-ng',font=self.headerfont, bg="white", padx=10, pady=10).grid(row = 0, column = 0)

        self.C21 = Checkbutton(self.frame_content3, text = "-o", \
                 onvalue = "-o", offvalue = "", height=1, \
                 width = 7, bg="white", font=self.customFont,variable=self.var21)
        self.C21.grid(row = 22, column = 0, padx = 5, pady = 5)
        self.t21=Text(self.frame_content3,height=1,width = 20)
        self.t21.grid(row = 22, column = 1, padx = 5, pady = 5)
        l21=Label(self.frame_content3, text = ': number of packets per burst (-1)',font=self.myfont, bg="white", justify=LEFT).grid(row = 22, column = 2, padx = 5, pady = 5)

        self.C22 = Checkbutton(self.frame_content3, text = "-q", \
                 onvalue = "-q", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var22)
        self.C22.grid(row = 24, column = 0, padx = 5, pady = 5)
        self.t22=Text(self.frame_content3,height=1,width = 20)
        self.t22.grid(row = 24, column = 1, padx = 5, pady = 5)
        l22=Label(self.frame_content3, text = ': seconds between keep-alives (-1)',font=self.myfont, bg="white", justify=LEFT).grid(row = 24, column = 2, padx = 5, pady = 5)

        self.C23 = Checkbutton(self.frame_content3, text = "-y", \
                 onvalue = "-y", offvalue = "", height=1, \
                 bg="white", font=self.customFont,variable=self.var23)


# This file is part of Scapy
# See http://www.secdev.org/projects/scapy for more information
# Copyright (C) Philippe Biondi <phil@secdev.org>
# This program is published under a GPLv2 license

"""
SMB (Server Message Block), also known as CIFS - version 2
"""

from scapy.config import conf
from scapy.packet import Packet, bind_layers, bind_top_down
from scapy.fields import (
    ConditionalField,
    FieldLenField,
    FieldListField,
    FlagsField,
    IntEnumField,
    IntField,
    LEIntField,
    LELongField,
    LEShortEnumField,
    LEShortField,
    PacketField,
    ReversePadField,
    ShortEnumField,
    ShortField,
    StrFieldUtf16,
    StrFixedLenField,
    UUIDField,
    XLEIntField,
    XLELongField,
    XLEShortField,
    XLongField,
    XNBytesField,
    XStrLenField,
)

# EnumField
SMB_DIALECTS = {
    0x0202: 'SMB 2.0.2',
    0x0210: 'SMB 2.1',
    0x0300: 'SMB 3.0',
    0x0302: 'SMB 3.0.2',
    0x0311: 'SMB 3.1.1',
}

# EnumField
SMB2_NEGOCIATE_CONTEXT_TYPES = {
    0x0001: 'SMB2_PREAUTH_INTEGRITY_CAPABILITIES',
    0x0002: 'SMB2_ENCRYPTION_CAPABILITIES',
    0x0003: 'SMB2_COMPRESSION_CAPABILITIES',
    0x0005: 'SMB2_NETNAME_NEGOCIATE_CONTEXT_ID',
}

# FlagField
SMB2_CAPABILITIES = {
    30: "Encryption",
    29: "DirectoryLeasing",
    28: "PersistentHandles",
    27: "MultiChannel",
    26: "LargeMTU",
    25: "Leasing",
    24: "DFS",
}

# EnumField
SMB2_COMPRESSION_ALGORITHMS = {
    0x0000: "None",
    0x0001: "LZNT1",
    0x0002: "LZ77",
    0x0003: "LZ77 + Huffman",
    0x0004: "Pattern_V1",
}

class SMB2_Header(Packet):
    name = "SMB2 Header"
    fields_desc = [
        StrFixedLenField("Start", b"\xfeSMB", 4),
        LEShortField("HeaderLength", 0),
        LEShortField("CreditCharge", 0),
        LEShortField("ChannelSequence", 0),
        LEShortField("Unused", 0),
        ShortEnumField("Command", 0, {0x0000: "SMB2_COM_NEGOCIATE"}),
        LEShortField("CreditsRequested", 0),
        # XLEIntField("Flags", 0),
        FlagsField("Flags", 0, 32, {
            24: "SMB2_FLAGS_SERVER_TO_REDIR",
        }),
        XLEIntField("ChainOffset", 0),
        LELongField("MessageID", 0),
        XLEIntField("ProcessID", 0),
        XLEIntField("TreeID", 0),
        XLELongField("SessionID", 0),
        XNBytesField("Signature", 0, 16),
    ]

    def guess_payload_class(self, payload):
        if self.Command == 0x0000:
            if self.Flags.SMB2_FLAGS_SERVER_TO_REDIR:
                return SMB2_Negociate_Protocol_Response_Header
            return SMB2_Negociate_Protocol_Request_Header
        return super(SMB2_Header, self).guess_payload_class(payload)

class SMB2_Compression_Transform_Header(Packet):
    name = "SMB2 Compression Transform Header"
    fields_desc = [
        StrFixedLenField("Start", b"\xfcSMB", 4),
        LEIntField("OriginalCompressedSegmentSize", 0x0),
        LEShortEnumField(
            "CompressionAlgorithm", 0,
            SMB2_COMPRESSION_ALGORITHMS
        ),
        ShortEnumField("Flags", 0x0, {
            0x0000: "SMB2_COMPRESSION_FLAG_NONE",
            0x0001: "SMB2_COMPRESSION_FLAG_CHAINED",
        }),
        XLEIntField("Offset/Length", 0),
    ]

class SMB2_Negociate_Context(Packet):
    name = "SMB2 Negociate Context"
    fields_desc = [
        LEShortEnumField("ContextType", 0x0, SMB2_NEGOCIATE_CONTEXT_TYPES),
        FieldLenField("DataLength", 0x0, fmt="<H", length_of="Data"),
        IntField("Reserved", 0),
    ]

class SMB2_Negociate_Protocol_Request_Header(Packet):
    name = "SMB2 Negociate Protocol Request Header"
    fields_desc = [
        XLEShortField("StructureSize", 0),
        FieldLenField(
            "DialectCount", None,
            fmt="<H",
            count_of="Dialects"
        ),
        # SecurityMode
        FlagsField("SecurityMode", 0, 16, {
            0x7: "Signing Required",
            0x8: "Signing Enabled",
        }),
        LEShortField("Reserved", 0),
        # Capabilities
        FlagsField("Capabilities", 0, 32, SMB2_CAPABILITIES),
        UUIDField("ClientGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
        XLEIntField("NegociateContextOffset", 0x0),
        FieldLenField(
            "NegociateCount", None,
            fmt="<H",
            count_of="NegociateContexts"
        ),
        ShortField("Reserved2", 0),
        FieldListField(
            "Dialects", [0x0202],
            LEShortEnumField("", 0x0, SMB_DIALECTS),
            count_from=lambda pkt: pkt.DialectCount
        ),
        # Field only exists if Dialects contains 0x0311
        # Each negotiate context must be 8-byte aligned
        ConditionalField(
            FieldListField(
                "NegociateContexts", [],
                ReversePadField(
                    PacketField("Context", None, SMB2_Negociate_Context), 8
                ), count_from=lambda pkt: pkt.NegociateCount
            ), lambda x: 0x0311 in x.Dialects
        ),
    ]

class SMB2_Preauth_Integrity_Capabilities(Packet):
    name = "SMB2 Preauth Integrity Capabilities"
    fields_desc = [
        # According to the spec, this field value must be greater than 0
        # (cf Section 2.2.3.1.1 of MS-SMB2.pdf)
        FieldLenField(
            "HashAlgorithmCount", 1,
            fmt="<H",
            count_of="HashAlgorithms"
        ),
        FieldLenField("SaltLength", 0, fmt="<H", length_of="Salt"),
        FieldListField("HashAlgorithms", [0x0001], LEShortEnumField("", 0x0, {
            # As for today, no other hash algorithm is described by the spec
            0x0001: "SHA-512",
        }), count_from=lambda pkt: pkt.HashAlgorithmCount),
        XStrLenField("Salt", "", length_from=lambda pkt: pkt.SaltLength),
    ]

class SMB2_Encryption_Capabilities(Packet):
    name = "SMB2 Encryption Capabilities"
    fields_desc = [
        # According to the spec, this field value must be greater than 0
        # (cf Section 2.2.3.1.2 of MS-SMB2.pdf)
        FieldLenField("CipherCount", 1, fmt="<H", count_of="Ciphers"),
        FieldListField("Ciphers", [0x0001], LEShortEnumField("", 0x0, {
            0x0001: "AES-128-CCM",
            0x0002: "AES-128-GCM",
        }), count_from=lambda pkt: pkt.CipherCount),
    ]

class SMB2_Compression_Capabilities(Packet):
    name = "SMB2 Compression Capabilities"
    fields_desc = [
        FieldLenField(
            "CompressionAlgorithmCount", 0,
            fmt="<H",
            count_of="CompressionAlgorithms"
        ),
        ShortField("Padding", 0x0),
        IntEnumField("Flags", 0x0, {
            0x00000000: "SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE",
            0x00000001: "SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED",
        }),
        FieldListField(
            "CompressionAlgorithms",
            None,
            LEShortEnumField("", 0x0, SMB2_COMPRESSION_ALGORITHMS),
            count_from=lambda pkt: pkt.CompressionAlgorithmCount,
        ),
    ]

class SMB2_Netname_Negociate_Context_ID(Packet):
    name = "SMB2 Netname Negociate Context ID"
    fields_desc = [
        StrFieldUtf16("NetName", "")
    ]

class SMB2_Negociate_Protocol_Response_Header(Packet):
    name = "SMB2 Negociate Protocol Response Header"
    fields_desc = [
        XLEShortField("StructureSize", 0),
        FlagsField("SecurityMode", 0, 16, {
            0x7: "Signing Required",
            0x8: "Signing Enabled",
        }),
        LEShortEnumField("Dialect", 0x0, SMB_DIALECTS),
        FieldLenField(
            "NegociateCount", None,
            fmt="<H",
            count_of="NegociateContexts"
        ),
        UUIDField("ServerGUID", 0x0, uuid_fmt=UUIDField.FORMAT_LE),
        # Capabilities
        FlagsField("Capabilities", 0, 32, SMB2_CAPABILITIES),
        LEIntField("MaxTransactionSize", 0),
        LEIntField("MaxReadSize", 0),
        LEIntField("MaxWriteSize", 0),
        # TODO FIXME
        XLongField("SystemTime", 0),
        XLongField("ServerStartTime", 0),
        XLEShortField("SecurityBufferOffset", 0),
        FieldLenField(
            "SecurityBufferLength", 0,
            fmt="<H",
            length_of="SecurityBuffer"
        ),
        XLEIntField("NegociateContextOffset", 0),
        # TODO FIXME
        XStrLenField(
            "SecurityBuffer", None,
            length_from=lambda pkt: pkt.SecurityBufferLength
        ),
        # Field only exists if Dialect is 0x0311
        # Each negotiate context must be 8-byte aligned
        ConditionalField(
            FieldListField(
                "NegociateContexts", [],
                ReversePadField(
                    PacketField("Context", None, SMB2_Negociate_Context), 8
                ), count_from=lambda pkt: pkt.NegociateCount


# This is a copy of the Python logging.config.dictconfig module.
# It is provided here for backwards compatibility for Python versions
# prior to 2.7.
#
# Copyright 2009-2010 by Vinay Sajip. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of Vinay Sajip
# not be used in advertising or publicity pertaining to distribution
# of the software without specific, written prior permission.
# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import logging.handlers
import re
import sys
import types

IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I)

def valid_ident(s):
    m = IDENTIFIER.match(s)
    if not m:
        raise ValueError('Not a valid Python identifier: %r' % s)
    return True

#
# This function is defined in logging only in recent versions of Python
#
try:
    from logging import _checkLevel
except ImportError:
    def _checkLevel(level):
        if isinstance(level, int):
            rv = level
        elif str(level) == level:
            if level not in logging._levelNames:
                raise ValueError('Unknown level: %r' % level)
            rv = logging._levelNames[level]
        else:
            raise TypeError('Level not an integer or a '
                            'valid string: %r' % level)
        return rv

# The ConvertingXXX classes are wrappers around standard Python containers,
# and they serve to convert any suitable values in the container. The
# conversion converts base dicts, lists and tuples to their wrapped
# equivalents, whereas strings which match a conversion format are converted
# appropriately.
#
# Each wrapper should have a configurator attribute holding the actual
# configurator to use for conversion.

class ConvertingDict(dict):
    """A converting dictionary wrapper."""

    def __getitem__(self, key):
        value = dict.__getitem__(self, key)
        result = self.configurator.convert(value)
        #If the converted value is different, save for next time
        if value is not result:
            self[key] = result
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
                result.key = key
        return result

    def get(self, key, default=None):
        value = dict.get(self, key, default)
        result = self.configurator.convert(value)
        #If the converted value is different, save for next time
        if value is not result:
            self[key] = result
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
                result.key = key
        return result

    def pop(self, key, default=None):
        value = dict.pop(self, key, default)
        result = self.configurator.convert(value)
        if value is not result:
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
                result.key = key
        return result

class ConvertingList(list):
    """A converting list wrapper."""
    def __getitem__(self, key):
        value = list.__getitem__(self, key)
        result = self.configurator.convert(value)
        #If the converted value is different, save for next time
        if value is not result:
            self[key] = result
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
                result.key = key
        return result

    def pop(self, idx=-1):
        value = list.pop(self, idx)
        result = self.configurator.convert(value)
        if value is not result:
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
        return result

class ConvertingTuple(tuple):
    """A converting tuple wrapper."""
    def __getitem__(self, key):
        value = tuple.__getitem__(self, key)
        result = self.configurator.convert(value)
        if value is not result:
            if type(result) in (ConvertingDict, ConvertingList,
                                ConvertingTuple):
                result.parent = self
                result.key = key
        return result

class BaseConfigurator(object):
    """
    The configurator base class which defines some useful defaults.
    """

    CONVERT_PATTERN = re.compile(r'^(?P<prefix>[a-z]+)://(?P<suffix>.*)$')

    WORD_PATTERN = re.compile(r'^\s*(\w+)\s*')
    DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*')
    INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*')
    DIGIT_PATTERN = re.compile(r'^\d+$')

    value_converters = {
        'ext' : 'ext_convert',
        'cfg' : 'cfg_convert',
    }

    # We might want to use a different one, e.g. importlib
    importer = __import__

    def __init__(self, config):
        self.config = ConvertingDict(config)
        self.config.configurator = self

    def resolve(self, s):
        """
        Resolve strings to objects using standard import and attribute
        syntax.
        """
        name = s.split('.')
        used = name.pop(0)
        try:
            found = self.importer(used)
            for frag in name:
                used += '.' + frag
                try:
                    found = getattr(found, frag)
                except AttributeError:
                    self.importer(used)
                    found = getattr(found, frag)
            return found
        except ImportError:
            e, tb = sys.exc_info()[1:]
            v = ValueError('Cannot resolve %r: %s' % (s, e))
            v.__cause__, v.__traceback__ = e, tb
            raise v

    def ext_convert(self, value):
        """Default converter for the ext:// protocol."""
        return self.resolve(value)

    def cfg_convert(self, value):
        """Default converter for the cfg:// protocol."""
        rest = value
        m = self.WORD_PATTERN.match(rest)
        if m is None:
            raise ValueError("Unable to convert %r" % value)
        else:
            rest = rest[m.end():]
            d = self.config[m.groups()[0]]
            #print d, rest
            while rest:
                m = self.DOT_PATTERN.match(rest)
                if m:
                    d = d[m.groups()[0]]
                else:
                    m = self.INDEX_PATTERN.match(rest)
                    if m:
                        idx = m.groups()[0]
                        if not self.DIGIT_PATTERN.match(idx):
                            d = d[idx]
                        else:
                            try:
                                n = int(idx) # try as number first (most likely)
                                d = d[n]
                            except TypeError:
                                d = d[idx]
                if m:
                    rest = rest[m.end():]
                else:
                    raise ValueError('Unable to convert '
                                     '%r at %r' % (value, rest))
        #rest should be empty
        return d

    def convert(self, value):
        """
        Convert values to an appropriate type. dicts, lists and tuples are
        replaced by their converting alternatives. Strings are checked to
        see if they have a conversion format and are converted if they do.
        """
        if not isinstance(value, ConvertingDict) and isinstance(value, dict):
            value = ConvertingDict(value)
            value.configurator = self
        elif not isinstance(value, ConvertingList) and isinstance(value, list):
            value = ConvertingList(value)
            value.configurator = self
        elif not isinstance(value, ConvertingTuple) and\
                 isinstance(value, tuple):
            value = ConvertingTuple(value)
            value.configurator = self
        elif isinstance(value, basestring): # str for py3k
            m = self.CONVERT_PATTERN.match(value)
            if m:
                d = m.groupdict()
                prefix = d['prefix']
                converter = self.value_converters.get(prefix, None)
                if converter:
                    suffix = d['suffix']
                    converter = getattr(self, converter)
                    value = converter(suffix)
        return value

    def configure_custom(self, config):
        """Configure an object with a user-supplied factory."""
        c = config.pop('()')
        if not hasattr(c, '__call__') and hasattr(types, 'ClassType') and type(c) != types.ClassType:
            c = self.resolve(c)
        props = config.pop('.', None)
        # Check for valid identifiers
        kwargs = dict([(k, config[k]) for k in config if valid_ident(k)])
        result = c(**kwargs)
        if props:
            for name, value in props.items():
                setattr(result, name, value)
        return result

    def as_tuple(self, value):
        """Utility function which converts lists to tuples."""
        if isinstance(value, list):
            value = tuple(value)
        return value

class DictConfigurator(BaseConfigurator):
    """
    Configure logging using a dictionary-like object to describe the
    configuration.
    """

    def configure(self):
        """Do the configuration."""

        config = self.config
        if 'version' not in config:
            raise ValueError("dictionary doesn't specify a version")
        if config['version'] != 1:
            raise ValueError("Unsupported version: %s" % config['version'])
        incremental = config.pop('incremental', False)
        EMPTY_DICT = {}
        logging._acquireLock()
        try:
            if incremental:
                handlers = config.get('handlers', EMPTY_DICT)
                # incremental handler config only if handler name
                # ties in to logging._handlers (Python 2.7)
                if sys.version_info[:2] == (2, 7):
                    for name in handlers:
                        if name not in logging._handlers:
                            raise ValueError('No handler found with '
                                             'name %r'  % name)
                        else:
                            try:
                                handler = logging._handlers[name]
                                handler_config = handlers[name]
                                level = handler_config.get('level', None)
                                if level:
                                    handler.setLevel(_checkLevel(level))
                            except StandardError, e:
                                raise ValueError('Unable to configure handler '
                                                 '%r: %s' % (name, e))
                loggers = config.get('loggers', EMPTY_DICT)
                for name in loggers:
                    try:
                        self.configure_logger(name, loggers[name], True)
                    except StandardError, e:
                        raise ValueError('Unable to configure logger '
                                         '%r: %s' % (name, e))
                root = config.get('root', None)
                if root:
                    try:
                        self.configure_root(root, True)
                    except StandardError, e:
                        raise ValueError('Unable to configure root '
                                         'logger: %s' % e)
            else:
                disable_existing = config.pop('disable_existing_loggers', True)

                logging._handlers.clear()
                del logging._handlerList[:]

                # Do formatters first - they don't refer to anything else
                formatters = config.get('formatters', EMPTY_DICT)
                for name in formatters:
                    try:
                        formatters[name] = self.configure_formatter(
                                                            formatters[name])
                    except StandardError, e:
                        raise ValueError('Unable to configure '
                                         'formatter %r: %s' % (name, e))
                # Next, do filters - they don't refer to anything else, either
                filters = config.get('filters', EMPTY_DICT)
                for name in filters:
                    try:
                        filters[name] = self.configure_filter(filters[name])
                    except StandardError, e:
                        raise ValueError('Unable to configure '
                                         'filter %r: %s' % (name, e))

                # Next, do handlers - they refer to formatters and filters
                # As handlers can refer to other handlers, sort the keys
                # to allow a deterministic order of configuration
                handlers = config.get('handlers', EMPTY_DICT)
                for name in sorted(handlers):
                    try:
                        handler = self.configure_handler(handlers[name])
                        handler.name = name
                        handlers[name] = handler
                    except StandardError, e:
                        raise ValueError('Unable to configure handler '
                                         '%r: %s' % (name, e))
                # Next, do loggers - they refer to handlers and filters

                #we don't want to lose the existing loggers,
                #since other threads may have pointers to them.
                #existing is set to contain all existing loggers,
                #and as we go through the new configuration we
                #remove any which are configured. At the end,
                #what's left in existing is the set of loggers
                #which were in the previous configuration but
                #which are not in the new configuration.
                root = logging.root
                existing = root.manager.loggerDict.keys()
                #The list needs to be sorted so that we can
                #avoid disabling child loggers of explicitly
                #named loggers. With a sorted list it is easier
                #to find the child loggers.
                existing.sort()
                #We'll keep the list of existing loggers
                #which are children of named loggers here...
                child_loggers = []
                #now set up the new ones...
                loggers = config.get('loggers', EMPTY_DICT)
                for name in loggers:
                    if name in existing: