#!/usr/bin/python
#   Unix SMB/CIFS implementation.
#   GTK+ Endpoint Mapper frontend
#
#   Copyright (C) Jelmer Vernooij 2004-2011
#
#   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 3 of the License, 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

#
# * Show:
# *  - RPC statistics
# *  - Available interfaces
# *   - Per interface: available endpoints
# *   - Per interface auth details
#

import gtk, gobject
import sambagtk
from samba.dcerpc import mgmt, epmapper

protocol_names = {
    epmapper.EPM_PROTOCOL_UUID: "UUID",
    epmapper.EPM_PROTOCOL_NCACN: "NCACN",
    epmapper.EPM_PROTOCOL_NCALRPC: "NCALRPC",
    epmapper.EPM_PROTOCOL_NCADG: "NCADG",
    epmapper.EPM_PROTOCOL_IP: "IP",
    epmapper.EPM_PROTOCOL_TCP: "TCP",
    epmapper.EPM_PROTOCOL_NETBIOS: "NetBIOS",
    epmapper.EPM_PROTOCOL_SMB: "SMB",
    epmapper.EPM_PROTOCOL_NAMED_PIPE: "PIPE",
    epmapper.EPM_PROTOCOL_UNIX_DS: "Unix",
}

def get_protocol_name(protocol):
    return protocol_names.get(protocol, "Unknown")


class EndpointBrowser(gtk.Window):

    def _on_quit1_activate (self, menuitem):
        gtk.main_quit()

    def _on_about1_activate(self, menuitem):
        aboutwin = sambagtk.AboutDialog("gepdump")
        aboutwin.run()
        aboutwin.destroy()

    def add_epm_entry(self, annotation, t):
        bd = t.as_binding_string()
        self._store_eps.append((0, annotation, 1, str(bd), 2, t))

        for floor in t.floors:
            if floor.lhs.protocol == epmapper.EPM_PROTOCOL_UUID:
                data = str(floor.get_lhs_data().uuid)
            else:
                data = floor.get_rhs_data()

            self._store_eps.append((0, get_protocol_name(floor.lhs.protocol), 1, data, -1))

    def refresh_eps(self):
        self._store_eps.clear()

        handle = None
        num_ents = max_ents = 10

        while num_ents == max_ents:
            (handle, num_ents, ents) = self._epmapper_pipe.Lookup(
                inquiry_type=0,
                object=uuid, interface_id=iface, vers_option=0,
                entry_handle=handle, max_ents=max_ents)
            for ent in ents:
                self.add_epm_entry(ent.annotation, ent.tower.tower)

    def _on_refresh_clicked(self, btn):
        self.refresh_eps()

    def _on_connect_clicked(self, btn):
        self._epmapper_pipe = sambagtk.RpcConnectDialog(epmapper.epmapper)

        self._mnu_refresh.set_sensitive(True)

        self.refresh_eps()

        self._mgmt_pipe = mgmt.mgmt(self._epmapper_pipe)

    def _on_eps_select(self, selection, model, path, path_currently_selected, data):
        # Do an InqStats call
        statistics = self._mgmt_pipe.inq_stats(max_count=mgmt.MGMT_STATS_ARRAY_MAX_SIZE,
                                         unknown=0)

        if statistics.count != mgmt.MGMT_STATS_ARRAY_MAX_SIZE:
            raise Exception("Unexpected array size %d" % statistics.count)

        self._lbl_calls_in.set_text("%6d" % statistics[mgmt.MGMT_STATS_CALLS_IN])
        self._lbl_calls_out.set_text("%6d" % statistics[mgmt.MGMT_STATS_CALLS_OUT])
        self._lbl_pkts_in.set_text("%wd" % statistics[mgmt.MGMT_STATS_PKTS_IN])
        self._lbl_pkts_out.set_text("%6d" % statistics[mgmt.MGMT_STATS_PKTS_OUT])

        self._store_princ_names.clear()

        for i in range(100):
            princ_name = self._mgmt_pipe.inq_princ_name(authn_proto=i, princ_name_size=100)
            name = gensec_get_name_by_authtype(i)
            if name is not None:
                protocol = "%u (%s)" % (i, name)
            else:
                protocol = "%u" % i

            self._store_princ_names.append((0, protocol, 1, princ_name))

        return True

    def __init__(self):
        super(EndpointBrowser, self).__init__()
        self._create()

    def _create(self):
        accel_group = gtk.AccelGroup()

        self.set_title("Gtk+ Endpoint Mapper Viewer")

        vbox1 = gtk.VBox(False, 0)
        vbox1.show()
        self.add(vbox1)

        menubar1 = gtk.MenuBar()
        menubar1.show()
        vbox1.pack_start(menubar1, False, False, 0)

        menuitem1 = gtk.MenuItem ("_File")
        menuitem1.show()
        menubar1.add(menuitem1)

        menuitem1_menu = gtk.Menu()
        menuitem1.set_submenu (menuitem1_menu)

        mnu_connect = gtk.MenuItem ("_Connect")
        menuitem1_menu.add(mnu_connect)

        self._mnu_refresh = gtk.MenuItem ("_Refresh")
        menuitem1_menu.add(self._mnu_refresh)
        self._mnu_refresh.set_sensitive(False)

        quit1 = gtk.ImageMenuItem(gtk.STOCK_QUIT, accel_group)
        menuitem1_menu.add(quit1)

        menuitem4 = gtk.MenuItem ("_Help")
        menubar1.add(menuitem4)

        menuitem4_menu = gtk.Menu()
        menuitem4.set_submenu (menuitem4_menu)

        about1 = gtk.MenuItem ("_About")
        menuitem4_menu.add(about1)

        hbox2 = gtk.HBox(False, 0)
        vbox1.add(hbox2)

        scrolledwindow1 = gtk.ScrolledWindow(None, None)
        hbox2.pack_start(scrolledwindow1, True, True, 0)

        tree_eps = gtk.TreeView()

        curcol = gtk.TreeViewColumn()
        curcol.set_title("Name")
        renderer = gtk.CellRendererText()
        curcol.pack_start(renderer, True)

        tree_eps.append_column(curcol)
        curcol.add_attribute(renderer, "text", 0)

        curcol = gtk.TreeViewColumn()
        curcol.set_title("Binding String")
        renderer = gtk.CellRendererText()
        curcol.pack_start(renderer, True)
        curcol.add_attribute(renderer, "text", 1)


        tree_eps.append_column(curcol)

        self._store_eps = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_POINTER)
        tree_eps.set_model(self._store_eps)

        scrolledwindow1.add(tree_eps)

        tree_eps.get_selection().set_select_function(self._on_eps_select, None, None)

        vbox2 = gtk.VBox(False, 0)
        hbox2.add(vbox2)

        frame1 = gtk.Frame("Interface")
        vbox2.add(frame1)

        vbox3 = gtk.VBox(False, 0)
        frame1.add(vbox3)
        lbl_iface_uuid = gtk.Label("")
        vbox3.add(lbl_iface_uuid)
        lbl_iface_version = gtk.Label("")
        vbox3.add(lbl_iface_version)
        lbl_iface_name = gtk.Label("")
        vbox3.add(lbl_iface_name)

        frame1 = gtk.Frame("Statistics")
        vbox2.add(frame1)

        table_statistics = gtk.Table(4, 2, True)
        frame1.add(table_statistics)

        table_statistics.attach(gtk.Label("Calls In: "), 0, 1, 0, 1)
        lbl_calls_in = gtk.Label("")
        table_statistics.attach(lbl_calls_in, 1, 2, 0, 1)
        table_statistics.attach(gtk.Label("Calls Out: "), 0, 1, 1, 2)
        lbl_calls_out = gtk.Label("")
        table_statistics.attach(lbl_calls_out, 1, 2, 1, 2)
        table_statistics.attach(gtk.Label("Packets In: "), 0, 1, 2, 3)
        lbl_pkts_in = gtk.Label("")
        table_statistics.attach(lbl_pkts_in, 1, 2, 2, 3)
        table_statistics.attach(gtk.Label("Packets Out: "), 0, 1, 3, 4)
        lbl_pkts_out = gtk.Label("")
        table_statistics.attach(lbl_pkts_out, 1, 2, 3, 4)

        frame1 = gtk.Frame("Authentication")
        vbox2.add(frame1)

        self._treeview_princ_names = gtk.TreeView()

        curcol = gtk.TreeViewColumn()
        curcol.set_title("Protocol")
        renderer = gtk.CellRendererText()
        curcol.pack_start(renderer, True)
        self._treeview_princ_names.append_column(curcol)
        curcol.add_attribute(renderer, "text", 0)

        curcol = gtk.TreeViewColumn()
        curcol.set_title("Principal Name")
        renderer = gtk.CellRendererText()
        curcol.pack_start(renderer, True)
        self._treeview_princ_names.append_column(curcol)
        curcol.add_attribute(renderer, "text", 1)

        frame1.add(self._treeview_princ_names)

        self._store_princ_names = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_POINTER)
        self._treeview_princ_names.set_model(self._store_princ_names)

        statusbar = gtk.Statusbar()
        vbox1.pack_start (statusbar, False, False, 0)

        quit1.connect("activate", self._on_quit1_activate)
        about1.connect("activate", self._on_about1_activate)
        mnu_connect.connect ("activate", self._on_connect_clicked)
        self._mnu_refresh.connect ("activate", self._on_refresh_clicked)

        self.add_accel_group (accel_group)


mainwin = EndpointBrowser()
mainwin.show_all()
gtk.main()
