"""
exploit_all.py

Copyright 2007 Andres Riancho

This file is part of w3af, http://w3af.org/ .

w3af 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 version 2 of the License.

w3af 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.

You should have received a copy of the GNU General Public License
along with w3af; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
"""
import gtk
import gobject

from w3af.core.controllers.exceptions import BaseFrameworkException, ScanMustStopException
from w3af.core.ui.gui.tabs.exploit.utils import get_exploitable_vulns, TextDialogConsumer


class ExploitAllDialog(gtk.Dialog):
    """A dialog with the About information.

    :author: Facundo Batista <facundobatista =at= taniquetil.com.ar>
    """
    def __init__(self, w3af):
        super(
            ExploitAllDialog, self).__init__("Multiple Exploit", None,
                                             gtk.DIALOG_MODAL,
                                             (gtk.STOCK_CANCEL,
                                              gtk.RESPONSE_CANCEL,
                                              gtk.STOCK_EXECUTE,
                                              gtk.RESPONSE_OK))

        self.liststore = gtk.ListStore(str, gobject.TYPE_BOOLEAN)

        # just build the tree with the plugin names
        for plugin in sorted(w3af.plugins.get_plugin_list("attack")):
            self.liststore.append([plugin, 1])

        # create the TreeView using liststore
        treeview = gtk.TreeView(self.liststore)
        self.vbox.pack_start(treeview)

        # create a TreeViewColumn for the text
        tvcolumn = gtk.TreeViewColumn(_('Exploits'))
        cell = gtk.CellRendererText()
        tvcolumn.pack_start(cell, True)
        tvcolumn.add_attribute(cell, 'text', 0)
        treeview.append_column(tvcolumn)

        # create a TreeViewColumn for the checkbox
        tvcolumn = gtk.TreeViewColumn(_('Active'))
        cell = gtk.CellRendererToggle()
        cell.set_property('activatable', True)
        cell.connect('toggled', self._toggle)
        tvcolumn.pack_start(cell, False)
        tvcolumn.add_attribute(cell, 'active', 1)
        treeview.append_column(tvcolumn)

        # stop on first
        self.but_sof = gtk.CheckButton(_("First successful"))
        if hasattr(self.but_sof, "set_tooltip_text"):
            self.but_sof.set_tooltip_text(
                _("Stop on first successful exploit"))
        self.vbox.pack_start(self.but_sof)

        # the cancel button
        but = self.action_area.get_children()[1]
        but.connect("clicked", lambda x: self.destroy())

        # the ok button
        but = self.action_area.get_children()[0]
        but.connect("clicked", self._ok)

        self.connect("delete-event", lambda x, y: self.destroy())
        self.enabled_plugins = None
        self.stopOnFirst = None
        self.show_all()

    def _ok(self, w):
        """Collects the information."""
        self.enabled_plugins = [name for (name, act) in self.liststore if act]
        self.stopOnFirst = self.but_sof.get_active()
        self.destroy()

    def _toggle(self, cell, path):
        """Toggles the plugin on/off.

        :param cell: the cell that generated the signal.
        :param path: the path that clicked the user.
        """
        listrow = self.liststore[path]
        listrow[1] = not listrow[1]


def effectively_exploit_all(w3af, enabled_plugins, stopOnFirst):
    """Exploit all the vulnerabilities.

    Just like in the 1-to-1 exploit, I'll create two generators that will
    perform the work in a "threaded" way.

    :param w3af: the core
    :param enabled_plugins: Which plugins are to be used.
    :param stopOnFirst: if the exploit should stop in the first exploited vuln.
    """
    dlg = TextDialogConsumer("Multiple Exploit!")

    # Start the generator that launches the exploit
    exploit_task = _launch_exploit_all(dlg, w3af, enabled_plugins,
                                       stopOnFirst)
    gobject.idle_add(exploit_task.next)


def _launch_exploit_all(dlg, w3af, enabled_plugins, stopOnFirst):
    """
    A generator that will perform the exploitation of all the vulnerabilities.

    :param dlg: The dialog where I'm going to write the messages
    :param w3af: the core
    :param enabled_plugins: Which plugins are to be used.
    :param stopOnFirst: if the exploit should stop in the first exploited vuln.
    """
    for exploit_name in enabled_plugins:
        dlg.add_message(_("\nExploiting %r...\n") % exploit_name)
        exploit = w3af.plugins.get_plugin_inst("attack", exploit_name)
        vulns = get_exploitable_vulns(exploit)
        dlg.add_message(_("  %d vulnerabilities to exploit\n") % len(vulns))

        yield True

        for vuln in vulns:

            # Let GTK handle events, I want a responsive GUI!
            yield True

            # check if o
            msg = _("Checking suitability for vuln %r...\n")
            dlg.add_message(msg % vuln.get_name())

            can_exploit = False

            try:
                can_exploit = exploit.can_exploit(vuln.get_id())
            except BaseFrameworkException, e:
                dlg.add_message(_("\nERROR: "))
                dlg.add_message(str(e) + '\n')
                dlg.done()
                dlg.dialog_run()
                yield False
            except ScanMustStopException, wmse:
                dlg.add_message(_("\nERROR: "))
                dlg.add_message(str(wmse) + '\n')
                dlg.done()
                dlg.dialog_run()
                yield False

            if not can_exploit:
                dlg.add_message(_("  nop\n"))
                yield True
                continue
            dlg.add_message(_("  ok\n"))

            # exploitable, go for it!
            dlg.add_message(_("Exploiting...\n"))
            try:
                exploit.exploit()
            except BaseFrameworkException, e:
                dlg.add_message(str(e) + '\n')
                yield True
                continue
            except ScanMustStopException, wmse:
                dlg.add_message(_("\nERROR:"))
                dlg.add_message(str(wmse) + '\n')
                dlg.done()
                dlg.dialog_run()
                yield False

            # Let GTK handle events, I want a responsive GUI!
            yield True

            # it was successful!
            if stopOnFirst:
                dlg.add_message(_("Done\n"))
                dlg.done()
                dlg.dialog_run()
                yield False

    dlg.add_message(_("Done\n"))
    dlg.done()
    dlg.dialog_run()
    yield False