# mount.py
# Copyright (C) 2008 Stefan J. Betz <stefan_betz@gmx.net>
#
# 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, see <http://www.gnu.org/licenses/>.

import pygtk
pygtk.require("2.0")
import gtk
import gobject
import threading
import re
import gettext
import os
from subprocess import Popen, PIPE, STDOUT
from tempfile import NamedTemporaryFile
from pyneighborhood import config, db
from pyneighborhood.misc import sharepath, homeconfdir, MountpointError, \
    push_notification, INFO, ERROR

_ = gettext.gettext

class MountWindow(threading.Thread):
    """
    Mount-dialog
    """

    def __init__(self, mainwindow, shareid = None, url = None):
        """
        Constructor
        """
        threading.Thread.__init__(self)
        self.mainwindow = mainwindow
        self.shareid = shareid
        if self.shareid != None:
            self.shareid = shareid
            cursor = db.cursor()
            self.share, self.host, self.ip, self.workgroup = cursor.execute("""
                SELECT shares.name, hosts.name, hosts.ip, workgroups.name
                FROM shares
                INNER JOIN hosts ON shares.host = hosts.id
                INNER JOIN workgroups ON hosts.workgroup = workgroups.id
                WHERE shares.id = ?""", (self.shareid,)).fetchone()
        elif not url:
            pass
        if not self.host:
            self.host = self.ip
        self.xml = gtk.Builder()
        self.xml.set_translation_domain('pyNeighborhood')
        self.xml.add_from_file(sharepath('ui/mountwindow.glade'))
        self.xml.connect_signals(self)

        self.window = self.xml.get_object("mount")
        
        self.workgroupentry = self.xml.get_object("workgroup-entry")
        self.workgroupentry.set_text(self.workgroup)
        self.hostentry = self.xml.get_object("host-entry")
        self.hostentry.set_text(self.host)
        self.shareentry = self.xml.get_object("share-entry")
        self.shareentry.set_text(self.share)
        self.anontoggle = self.xml.get_object("anonymous-button")
        self.authtoggle = self.xml.get_object("user-pass-button")
        self.user = self.xml.get_object("user-entry")
        self.user.set_text(config.get("Main", "username"))
        self.password = self.xml.get_object("pass-entry")
        self.password.set_text(config.get("Main", "password"))
        self.individual = self.xml.get_object("individual-button")
        self.choose_mountpoint = self.xml.get_object("mountpoint-chooser")
        if os.access(config.get("Main", "mount_directory"), os.F_OK):
            self.choose_mountpoint.set_current_folder(config.get("Main", "mount_directory"))
        self.errorre = re.compile("^.* ([0-9]+) = (.*)")

    def logon_toggle(self, widget):
        """
        Logon Options Toggle Callback
        """
        if self.authtoggle.get_active() == True:
            self.user.set_sensitive(True)
            self.password.set_sensitive(True)
        else:
            self.user.set_sensitive(False)
            self.password.set_sensitive(False)
    
    def mountpoint_toggled(self, button):
        """
        Individual Mountpoint Toggle Callback
        """
        if button.get_active() == True:
            self.choose_mountpoint.set_sensitive(True)
        else:
            self.choose_mountpoint.set_sensitive(False)

    def response_handler(self, widget, response_id):
        """
        Response Handler
        """
        if response_id == gtk.RESPONSE_CANCEL:
            self.window.destroy()
        elif response_id == gtk.RESPONSE_OK:
            self.start()
            
    def create_mountpoint(self):
        """
        Create the mountpoint
        """
        basedir = config.get("Main", "mount_directory")
        workgroupdir = os.path.join(basedir, self.workgroup)
        hostdir = os.path.join(basedir, self.workgroup, self.host)
        mountpoint = os.path.join(basedir, self.workgroup, self.host, self.share)
        if not os.access(basedir, os.R_OK + os.W_OK + os.X_OK):
            if not os.path.isdir(basedir):
                try:
                    os.mkdir(basedir)
                except OSError, e:
                    raise MountpointError("Error creating mount directory: %s" % e)
            else:
                raise MountpointError("Error accessing mount directory: "\
                                      "Lack of permission to access %s" % basedir)
        try:
            if not os.path.exists(workgroupdir):
                os.mkdir(workgroupdir)
            if not os.path.exists(hostdir):
                os.mkdir(hostdir)
            if not os.path.exists(mountpoint):
                os.mkdir(mountpoint)
            return mountpoint
        except OSError, e:
            raise MountpointError("Error creating mount directory: %s" % e)

    def mount(self, username=None, password=None, target=None):
        """
        Mounting Shares...
        """
        error = None
        options = []
        command = []
        if config.get("Main", "enable_sudo") == "True":
            command.append(config.get("Main", "sudo"))
        command.append(config.get("CIFS", "mount"))
        if len(config.get("CIFS", "options")) > 0:
            options.append(config.get("CIFS", "options"))
        command.append("//" + self.ip + "/" + self.share)
        if target != None:
            if os.path.exists(target):
                mountpoint = target
            else:
                error = _("The specified mount directory does not exist!")
                return (target, error)
        else:
            try:
                mountpoint = self.create_mountpoint()
            except MountpointError, e:
                return (None, e)
        command.append(mountpoint)
        if username == None or password == None:
            options.append("guest")
            options.append("sec=none")
        else:
            credentials = NamedTemporaryFile(dir=homeconfdir(),prefix="smbcreds")
            credentials.write('username=%s\n' % (username))
            credentials.write('password=%s\n' % (password))
            credentials.flush()
            options.append( "credentials=%s" % (credentials.name))
        if len(options) != 0:
            command.append("-o")
            command.append(",".join(options))
        process = Popen(command, executable = command[0], stdout=PIPE, stderr=PIPE)
        stdout, stderr = process.communicate()
        try:
            credentials.close()
            del credentials
        except UnboundLocalError:
            pass
        if len(stderr) != 0:
            return (mountpoint, stderr)
        else:
            gobject.idle_add(self.window.destroy)
            return (mountpoint, None)

    def run(self):
        """
        Make it real!
        """
        self.mountpoint = self.choose_mountpoint.get_current_folder()
        self.individual_toggle = self.individual.get_active()
        if self.anontoggle.get_active() == True:
            if self.individual_toggle == True:
                mountpoint, error = self.mount(target=self.mountpoint)
            elif self.individual_toggle == False:
                mountpoint, error = self.mount()
        elif self.authtoggle.get_active() == True:
            if self.individual_toggle == True:
                mountpoint, error = self.mount(username=self.user.get_text(), password=self.password.get_text(), target=self.mountpoint)
            elif self.individual_toggle == False:
                  mountpoint, error = self.mount(username=self.user.get_text(), password=self.password.get_text())
        if error != None:
            push_notification(_("Error mounting //%(ip)s/%(share)s: %(error)s!\n") % { "ip": self.ip, "share": self.share, "error": str(error).strip() }, ERROR)
            self.window.destroy()
        else:
            push_notification(_("Mounted //%(ip)s/%(share)s successfully.\n") % { "ip": self.ip, "share": self.share }, INFO)
            gtk.gdk.threads_enter()
            if config.get("Main", "enable_file_manager") == "True":
                fmcmd = [config.get("Main", "filemanager"), mountpoint]
                push_notification(_("Launching %(cmd)s for %(mp)s...\n") % { "cmd": fmcmd[0], "mp": fmcmd[1] }, INFO)
                fmpid = Popen(fmcmd, executable=fmcmd[0], stderr=PIPE)
            gtk.gdk.threads_leave()
            self.mainwindow.reload_mounts()
            self.window.destroy()
