#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3

import os

from winswitch.util.main_loop import with_loop, loop_exit
from winswitch.util.commands_util import KEYGEN_COMMAND
from winswitch.util.file_io import get_client_dir
from winswitch.util.common import csv_list, is_valid_dir
from winswitch.util.process_util import twisted_exec
from winswitch.util.paths import PUTTY_DIR
from winswitch.util.simple_logger import Logger

logger=Logger("ssh_key_util", log_colour=Logger.CYAN)

def get_new_key_filename():
	"""
	Returns a filename that does not exist yet, so we can use it to store our new key.
	"""
	client_dir = get_client_dir()
	i = 0
	while i<10000:
		filename = os.path.join(client_dir, "ssh-key-%d" % i)
		if not os.path.exists(filename):
			return	filename
		i += 1
	raise Exception("Too many failed attempts at finding a free key filename")

def generate_new_key(call_when_done_with_filenames):
	low = KEYGEN_COMMAND.lower()
	if low.find("ssh-keygen")>=0:
		#SSH is easy:
		#We simply choose a new filename, call ssh-keygen and when it terminates we call_when_done_with_filename on the filenames we chose
		filename = get_new_key_filename()
		args = [KEYGEN_COMMAND, "-t", "rsa", "-q", "-f", filename, "-N", ""]
		def keygen_done(output):
			call_when_done_with_filenames("%s.pub" % filename, filename)
		twisted_exec(args, keygen_done)
	elif low.find("putty")>=0:
		putty_keygen(call_when_done_with_filenames)
	else:
		logger.serror("unknown key command: %s" % KEYGEN_COMMAND, call_when_done_with_filenames)

def putty_keygen(call_when_done_with_filenames):
	"""
	We call putty from the PuTTY directory where we installed it after getting the list of files.
	Hopefully the user will save it there too... and we can detect it.
	Otherwise, the user will have to select it by hand in the UI.
	"""
	cwd = None
	file_info = {}
	if PUTTY_DIR and is_valid_dir(PUTTY_DIR):
		cwd = PUTTY_DIR
		names = os.listdir(cwd)
		for name in names:
			try:
				file_info[name] = os.path.getmtime(os.path.join(cwd, name))
			except os.error:
				continue
	def putty_keygen_done(output):
		logger.sdebug(None, output)
		detect_putty_keys(output, cwd, file_info, call_when_done_with_filenames)
	twisted_exec([KEYGEN_COMMAND], putty_keygen_done, path=cwd)

def detect_putty_keys(output, cwd, file_info, call_when_done_with_filenames):
	"""
	This is called when puttygen.exe exits. We try to find the files that it has created for us.
	"""
	logger.sdebug(None, output, cwd, file_info, call_when_done_with_filenames)
	if not cwd or not is_valid_dir(cwd):
		#cant guess if the user has created new files...
		return

	#try to find a new file(s) with the expected extension:
	names = os.listdir(cwd)
	priv_filename = None
	pub_filename = None
	candidates = []
	for name in names:
		filename = os.path.join(cwd, name)
		mod = os.path.getmtime(os.path.join(cwd, name))
		#either a new file, or one which has been modified since we launched puttygen:
		if (name not in file_info.keys()) or (mod!=file_info[name]):
			candidates.append(name)
			low = name.lower()
			if low.find(".ppk")>0 or low.find("private")>=0:
				logger.slog("found new private key file: %s" % name, output, cwd, file_info, call_when_done_with_filenames)
				priv_filename = filename
			if low.find("public")>=0:
				logger.slog("found new public key file: %s" % name, output, cwd, file_info, call_when_done_with_filenames)
				pub_filename = filename
	if priv_filename:
		call_when_done_with_filenames(priv_filename, pub_filename)
	if len(candidates)>0:
		logger.sdebug("found some new files: %s, but unsure of which one to use, cowardly bailing out" % csv_list(candidates), output, cwd, file_info, call_when_done_with_filenames)
		return


def test_generate_result(*args):
	logger.slog(None, args)
	loop_exit()

def main():
	with_loop(test_generate_result)


if __name__ == "__main__":
	main()
