#! /usr/bin/env python

# kate, process the output of a GPG import and make changelog entries from it
# Copyright (C) 2000  James Troup <james@nocrew.org>

# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# NB: this code is a *horrible* mess.  It's intended to be functional,
# nothing more.  Please don't read it, it's embarassing.

import sys, string, commands, time, shutil, os, tempfile, getopt

#####################################################################

def open_file(filename, mode):
	try:
		f = open(filename, mode)
	except IOError:
		sys.stderr.write('Cannot open '+filename+'.\n')
		sys.exit(2)
	return f

# From reportbug
def our_raw_input():
    sys.stdout.flush()
    try:
        ret = raw_input()
        return ret
    except EOFError:
        sys.stderr.write('\nUser interrupt (^D).\n')
        raise SystemExit

#####################################################################

allow_add = 'no'
gpg_opts = '--emulate-md-encode-bug --no-options --no-default-keyring --always-trust'
pgp_opts = '' # --load-extension rsa if << 1.0.3-1
gpg_prog = 'gpg'
keys_path = '/home/james/debian/debian-keyring/debian-keyring/keyrings/'
changelog_path = '/home/james/debian/debian-keyring/debian-keyring/debian/changelog'
gpg_keys = [ 'debian-keyring.gpg', 'debian-keyring.pgp' ]
maintainer = 'James Troup <james@nocrew.org>'
dest_keyring = 'debian-keyring'
action = ''
key_type = 'gpg'

#####################################################################

def generate_log(allow_add, import_key):
	updated = {}
	added = {}
	log = open_file ('foo', 'r')

	for line in log.readlines():
		if line[:5] != 'gpg: ':
			sys.stderr.write('Found non-standard line :' + line[:-1])
			sys.exit(2)
		if line[:9] == 'gpg: key ':
			msg = line[19:-1]
			keyid = '0x'+line[9:17]
			if allow_add == 'yes' and string.find(msg, 'public key imported') != -1:
				added[keyid] = ''
			elif msg != 'not changed' and msg != 'duplicated user ID detected - merged':
				if not updated.has_key(keyid):
					updated[keyid] = {}
				if string.find(msg, 'new signature') != -1:
					if not updated[keyid].has_key('sig'):
						updated[keyid]['sig'] = 0
					updated[keyid]['sig'] = updated[keyid]['sig'] + int(string.split(msg)[0])
				elif string.find(msg, 'new user ID') != -1:
					if not updated[keyid].has_key('uid'):
						updated[keyid]['uid'] = 0
					updated[keyid]['uid'] = updated[keyid]['uid'] + int(string.split(msg)[0])
				elif string.find(msg, 'new subkey') != -1:
					if not updated[keyid].has_key('sub'):
						updated[keyid]['sub'] = 0
					updated[keyid]['sub'] = updated[keyid]['sub'] + int(string.split(msg)[0])
				elif string.find(msg, 'revocation certificate added') != -1:
					updated[keyid]['rev'] = ''
				else:
					sys.stderr.write('Found non-standard line :' + line[:-1])
					sys.exit(2)

	i = 0
	log = []
	for keyid in added.keys():
		fingerprint = commands.getoutput('%s %s --keyring=./old --fingerprint %s | head -n 1' % (gpg_prog, gpg_opts, keyid))
		key = fingerprint[5:20] + fingerprint[31:]
		log.append('')
		log[i] = '  * [%s] {Added%s} %s\n' % (time.strftime('%a, %d %b %Y %H:%M:%S %Z', time.localtime(time.time())), action, key)
		i = i + 1
	for keyid in updated.keys():
		keyrings = ''
		for keyring in gpg_keys:
			keyrings = keyrings + ' --keyring='+keys_path+keyring
		fingerprint = commands.getoutput('%s %s %s --fingerprint %s | head -n 1' % (gpg_prog, gpg_opts, keyrings, keyid))
		key = fingerprint[5:20] + fingerprint[31:]
		log.append('')
		log[i] = '  * [%s] {Update} %s (' % (time.strftime('%a, %d %b %Y %H:%M:%S %Z', time.localtime(time.time())), key)
		if updated[keyid].has_key('uid'):
			log[i] = log[i] + 'uid: %d' % (updated[keyid]['uid'])
		if updated[keyid].has_key('sig'):
			if updated[keyid].has_key('uid'):
				log[i] = log[i] + ', '
			log[i] = log[i] + 'sig: %d' % (updated[keyid]['sig'])
		if updated[keyid].has_key('sub'):
			if updated[keyid].has_key('uid') or updated[keyid].has_key('sig'):
				log[i] = log[i] + ', '
			log[i] = log[i] + 'sub: %d' % (updated[keyid]['sub'])
		if updated[keyid].has_key('rev'):
			if updated[keyid].has_key('uid') or updated[keyid].has_key('sig') or updated[keyid].has_key('sub'):
				log[i] = log[i] + ', '
			log[i] = log[i] + 'rev'
		log[i] = log[i] + ')\n'
		i = i + 1
	return log

#####################################################################

def add_to_changelog(update):
	changelog_file = open_file (changelog_path, 'r')
	changelog = changelog_file.readlines()

	i = 0
	for line in changelog:
		if line[:4] == ' -- ':
			changelog.pop(i)
			changelog.pop(i)
			date = commands.getoutput('date -R')
			changelog.insert(i-1, ' -- %s  %s\n' % (maintainer, date))
			changelog.insert(i-1, '\n')
			update.reverse()
			for update_line in update:
				changelog.insert(i-1, update_line)
			break
		i = i + 1

	new_file = open_file ('baz', 'w')
	for line in changelog:
		new_file.write(line)
	new_file.close()
	shutil.copyfile('./baz', changelog_path)

#####################################################################

def do_import (import_keyring, type):
	keyring = '%s/%s.%s' % (keys_path, dest_keyring, type)
	shutil.copy2(keyring, './old')
	command = '%s %s --keyring=./old --fast-import %s 2> foo' % (gpg_prog, gpg_opts, import_keyring)
	#print 'Running "' + command + '"...'
	print 'Importing into temporary keyring...'
	sts = os.system (command)
	if sts != 0:
		sys.stderr.write('"' + command + '" failed with exit code ' + repr(sts) + '.\n')
		foobar = open_file ('foo', 'r')
		for line in foobar.readlines():
			print line,
		sys.exit(sts)

def do_real_import (import_keyring, type):
	keyring = '%s/%s.%s' % (keys_path, dest_keyring, type)
	command = '%s %s --keyring=%s --fast-import %s 2> /dev/null' % (gpg_prog, gpg_opts, keyring, import_keyring)
	print 'Importing into live keyring...'
	sts = os.system (command)
	if sts != 0:
		sys.stderr.write('"' + command + '" failed with exit code ' + repr(sts) + '.\n')
		sys.exit(sts)

def setup_tempdir ():
	tmpdir = tempfile.mktemp('')
	os.mkdir(tmpdir)
	os.chdir(tmpdir)
	#print tmpdir

def main():
	global gpg_opts, dest_keyring, key_type, allow_add, action
	try:
		(opts, args) = getopt.getopt(sys.argv[1:],
					     'adehk:rt:vu:',
					     ['add', 'debug', 'emeritus', 'help', 'keyring=', 'remove', 'type=', 'user=', 'version'])
	except getopt.error, msg:
		sys.stderr.write(msg+'\n')
		sys.exit(1)

	for option, arg in opts:
		if option in ('-a', '--allow-add'):
			allow_add = 'yes'
		if option in ('-h', '--help'):
			return
		elif option in ('-d', '--debug'):
			return
                elif option in ('-e', '--emeritus'):
			dest_keyring = 'emeritus'
                elif option in ('-k', '--keyring='):
			if arg == 'extra':
				dest_keyring = 'extra-keys'
				key_type = 'pgp'
				action = ' [Extra]'
			else:
				sys.stderr.write('Eh? ' + arg + '\n')
				sys.exit(2)
                elif option in ('-r', '--remove'):
			dest_keyring = 'removed-keys'
			action = ' [Removed]'
                elif option in ('-t', '--type'):
			key_type = arg
		elif option in ('-u', '--user'):
			user = arg
		elif option in ('-v', '--version'):
			return

	if key_type == 'pgp':
		gpg_opts = gpg_opts + pgp_opts

	olddir = os.getcwd()
	setup_tempdir()
	# Fix me, you slapper, this won't work for absolute paths
	import_key = args[0]
	if import_key[:1] != '/':
		import_key = olddir + '/' + import_key
	do_import (import_key, key_type)
	log = generate_log(allow_add, import_key)
	print
	for line in log:
		print line,
	print '\n Continue (y/N)? ',
	yn = our_raw_input()
	if yn == 'Y'  or yn == 'y':
		do_real_import (import_key, key_type)
		add_to_changelog(log)
	os.chdir(olddir)

if __name__ == '__main__':
    main()
	
