#!/usr/bin/python
#
#    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, version 2 of the License only.
#
#    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.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#    tpm_keyring
#
#    Release 0.1
#
#    Copyright (C) Kent E. Yoder <kyoder@users.sf.net>, 2006
#

from qt import *
from qttable import QTable
from optparse import OptionParser

import cPickle
import sys
import posix
import os
import pwd
import errno

from tpm_keyring_util import *


SAVE_PATH_MODE = 0700
CONFIG_DATA_MODE = 0600
#
#
# The default save path is $(HOME)/SAVE_DIR
#
# In this directory, 3 sets of data will be stored:
# 1. The configuration data for tpm_keyring (the list of groups/members, etc)
# 2. The OpenSSL PEM software key files for each group
# 3. The TSS key store for the TPM based keys used by each group (created by TSS)
#
# These 3 sets of data need to stay in sync, or tpm_keyring will throw errors.
#
# If you'd like to change the location that tpm_keyring stores this data, set
# SAVE_PATH to some path. SAVE_PATH/SAVE_DIR will become the new directory to
# store the 3 sets of data in. All components of the path must already exist up
# to the SAVE_DIR, which will be created if it doesn't exist.
#
# SAVE_PATH = "/media/usb"
SAVE_PATH = None
SAVE_DIR = "/.tpmkeyring2"
CONFIG_DATA_PATH = "/tpmkeyring2_config_data"
CONFIG_TSS_KEYSTORE_PATH = "/tpmkeyring2_tpm_keys"

CONFIG_APP_STR = "TPM Keyring"
CONFIG_FONT_SIZE = 8



########################################################################
#
# icon data
#
copy_image_data = \
    "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d" \
    "\x49\x48\x44\x52\x00\x00\x00\x10\x00\x00\x00\x10" \
    "\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\x00\x00\x02" \
    "\x41\x49\x44\x41\x54\x38\x8d\x85\x92\x4b\x4e\x54" \
    "\x51\x10\x86\xbf\x3a\xe7\xdc\xdb\xdd\x34\xa8\x04" \
    "\x90\xee\x10\x4d\xa4\xd1\x40\x0c\x60\x08\x12\x7a" \
    "\x62\x88\x3b\x70\x05\x26\xee\xc0\x05\xb8\x01\x71" \
    "\x05\x9a\xe0\xcc\x2d\x98\x9e\x31\xe9\x30\x70\x60" \
    "\x48\x9a\x44\x20\x31\x4e\x1c\x41\x82\xe1\xde\xdb" \
    "\x8f\x7b\xcf\xc3\x01\xef\x87\xb1\x66\x55\x95\xfa" \
    "\xcf\x5f\x5f\x1d\x69\xb7\xf7\x8e\x46\x47\x87\x4d" \
    "\x08\x1e\x6b\x3d\xde\x07\x94\xd2\xec\xec\xfc\x1c" \
    "\xde\xde\xfe\xf1\x26\x8a\xcc\x67\x80\xa2\xb0\xac" \
    "\xad\x3d\x07\x60\x73\xf3\x1b\x51\x64\x00\x30\x95" \
    "\x8a\x19\x9e\x9d\xad\x9d\x64\x40\x51\x40\x9a\x0e" \
    "\x88\x63\x0d\xb0\xd1\xe9\xec\x8d\x2b\xa5\xd6\x43" \
    "\x08\xdc\x16\xea\x7a\x41\x6b\x88\xe3\x98\xfd\xfd" \
    "\xdf\x1c\x1e\x1e\x51\x2e\x97\xde\x5b\xeb\xde\x19" \
    "\xa3\x51\x4a\xfe\x2f\x20\x02\xce\x59\x16\x16\x66" \
    "\x58\x59\x79\xca\xdc\xdc\x34\x22\xf2\xa8\xd9\x7c" \
    "\xc6\xc8\xc8\x30\xd7\x9d\x98\xdb\x04\xb4\xd6\x1c" \
    "\x1f\x77\xe9\xf5\x72\xee\xdc\xa9\xd2\x6c\x2e\xbc" \
    "\x98\x98\xb8\xf7\xb1\x28\x6c\x05\xa8\x86\x10\xbe" \
    "\x7a\xef\x3f\x29\xa5\x6e\x0a\x64\x19\x1c\x1d\xa5" \
    "\xa4\x69\xca\xd2\xd2\x34\x23\x23\x31\x40\x23\xcb" \
    "\x68\x24\x49\x46\x51\x38\xb2\xac\xff\xaa\xd3\xd9" \
    "\xbb\x5b\x14\xf6\xc3\x15\x81\x7e\x1f\xba\xdd\x3e" \
    "\x4a\x69\xb4\xd6\x94\x4a\x17\xed\x6a\x15\xbc\xaf" \
    "\x70\x70\xf0\x87\x24\x49\x28\x97\xcb\xeb\x83\x41" \
    "\x72\xff\x9c\x41\x08\x90\xe7\x05\xc6\x28\xca\x65" \
    "\x83\x88\x70\x1d\xbc\x31\x42\x1c\x47\xd4\xeb\x13" \
    "\xcc\xcc\x3c\x64\x68\xa8\xfc\xf6\x5c\x20\xcf\x41" \
    "\x44\x23\x37\x41\x5f\x10\x57\x42\xa9\x14\x31\x39" \
    "\x39\xc6\xd4\xd4\x38\xc6\x44\x18\xa5\x2e\x0e\x61" \
    "\x8c\xa0\x94\xc1\x39\xb8\x5c\x3f\x8b\x6e\x37\x27" \
    "\x4d\xbb\x78\x1f\xa8\x54\x4a\x88\x08\x26\x49\x7a" \
    "\x24\x49\x41\x92\xf4\xf1\x3e\xe0\xbd\xc7\xb9\x40" \
    "\x9e\x5b\xe4\x92\x9d\x24\xf1\x64\xd9\x80\x10\x84" \
    "\x6a\xb5\x82\xd6\x1a\x63\xc0\xb4\x5a\x5b\x5f\x5a" \
    "\xad\xad\x2b\xcf\xf5\x7a\x83\xde\xfc\xfc\xe3\x97" \
    "\xab\xab\xd3\x8d\x33\xb8\xd6\x16\xc4\xb1\x41\x29" \
    "\x85\x52\x72\xea\x50\x30\xc0\xeb\xcb\xc3\x79\x6e" \
    "\xa9\xd5\xc6\xa8\xd5\xc6\x36\xbc\xa7\xa1\x14\x38" \
    "\xe7\xd1\x5a\x61\x6d\x40\x6b\x85\xd6\x0a\x11\x7d" \
    "\xb2\xf6\xe5\xe1\xa2\xb0\xd4\xeb\x13\x2c\x2f\xcf" \
    "\xe2\x1c\x38\x17\xb0\x56\x80\x93\x55\xb4\x16\xbc" \
    "\xff\xc7\x4f\x74\xce\xd3\x68\x3c\x60\x71\xf1\x09" \
    "\x21\x04\x42\x28\x00\x21\x8a\x40\x44\xf0\x3e\x42" \
    "\xc4\x23\x62\x01\x10\x51\x27\x10\xcf\x04\x44\x20" \
    "\xcb\xfa\xb4\xdb\xdf\x01\x08\x21\x0c\x76\x77\x7f" \
    "\x01\xa4\xa7\x39\xce\x71\xda\x73\x88\x40\x9a\xf6" \
    "\xec\x5f\x8e\xf6\xf5\x80\xc5\x80\xfc\x57\x00\x00" \
    "\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82"

blue_play_image_data = \
    "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d" \
    "\x49\x48\x44\x52\x00\x00\x00\x10\x00\x00\x00\x10" \
    "\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\x00\x00\x02" \
    "\x3d\x49\x44\x41\x54\x38\x8d\x85\xd3\x4d\x48\x54" \
    "\x51\x14\xc0\xf1\xff\x7d\x33\xf3\x26\x53\x2b\x63" \
    "\xd0\x94\x3e\xa8\x48\xca\x45\x20\x25\x51\xf4\xe9" \
    "\xa2\x4d\x6d\xa2\x20\xa2\x48\x22\x2a\xb0\x45\xad" \
    "\x8a\x3e\x10\x82\x20\x48\x6c\x13\xd4\x4e\x28\x08" \
    "\x2a\x0b\x43\xcc\xa5\xe5\x22\x82\x08\x92\x2c\x08" \
    "\x23\x3f\x0b\xbf\x90\x71\x9e\x6f\x66\xde\x7b\xf7" \
    "\xbe\x77\x5b\x8c\xbe\x1c\xc5\x3c\x70\xe0\x2e\xee" \
    "\xf9\x71\xce\xe1\x5e\xa1\xb5\x06\xa0\xf2\xfc\xbb" \
    "\x7a\xcf\x30\x1b\x5c\x61\x26\xc4\xe4\xc4\xd7\x68" \
    "\xc6\xbe\xe3\x2b\xbf\x4d\xa5\x1d\x2d\xd3\x59\x54" \
    "\xc6\x41\xd9\x59\x94\x9d\x45\x66\x5c\xb4\xdf\x08" \
    "\x80\xc1\x4c\x38\x41\xa4\x71\xeb\xee\xed\x65\x8f" \
    "\xae\xd7\x44\x76\xd4\x56\x57\x5b\x2c\x6b\xf5\x1d" \
    "\xef\x2e\x4b\x44\x08\xf8\x1a\x63\xd3\xfa\x62\x8e" \
    "\x6d\x86\x7b\xa7\xca\x39\x7c\xe6\x90\xc8\x24\xd6" \
    "\xde\x74\xb3\xee\x13\xa1\x75\xc9\x92\x00\x52\x31" \
    "\x95\x85\x2f\xa3\x90\x76\xe0\x4a\x6d\x31\x17\xeb" \
    "\x0f\xb2\x7c\x5b\xd5\x59\xd7\x55\xad\x04\x7a\xcb" \
    "\x7f\x81\x40\x2a\xa6\x3d\x18\x4e\x41\x7f\x12\x7e" \
    "\x27\x61\xff\xc6\x08\xe7\x2e\xed\x63\xf5\xde\x3d" \
    "\x07\x1c\x37\x68\x47\xca\x9d\x20\x16\x01\x3c\x1f" \
    "\xcb\x83\x41\x0b\x86\x2d\x18\x4a\x41\xef\x04\x54" \
    "\x14\x09\x4e\xd6\xd5\xb0\xee\xc4\x91\x4a\x27\x12" \
    "\x6f\x0f\x5c\xf7\xb8\x40\x87\x40\x74\xf6\xa0\xa5" \
    "\x64\xda\x85\xfe\x29\xf0\xfc\xfc\x36\xe3\x31\xa8" \
    "\x3d\x5a\x45\x67\x41\x61\x59\x5f\xf3\x8b\x67\x8c" \
    "\x8f\x54\x00\x0f\xf3\x00\x5f\x29\x52\x5e\x0e\x50" \
    "\x41\xb8\x58\x04\x10\x31\x20\x6a\x40\xd5\xae\x0d" \
    "\xa4\x63\x75\xf1\xb1\x07\x8f\xef\x2f\x00\xb4\xa7" \
    "\x48\x39\xf0\x2b\x09\xc1\x4c\x87\x81\x06\x44\x0e" \
    "\x92\x0a\x88\x83\xa3\xc8\x5b\x43\x08\x04\x9e\xc2" \
    "\x76\xc0\x73\x08\x27\xd4\x1a\x64\x90\x4b\x6d\x02" \
    "\xdd\x7d\xd0\xfa\xdc\xc5\x9e\xba\xb6\x10\x90\x0a" \
    "\xe9\xe5\x2e\xe7\xaa\x67\xd2\x00\x11\x03\x3e\x75" \
    "\xc3\xdb\x96\x31\xb2\xd6\x65\x30\x5f\x2f\x00\x90" \
    "\x8a\x15\x26\xa0\xfe\xb5\x27\x0c\x80\x80\x4c\xe7" \
    "\x7b\x64\x67\x47\x2f\xbe\x77\x1a\xcc\xcf\x73\x17" \
    "\x1c\x02\x86\xaf\x28\x2d\x02\x2d\x73\x33\x1a\x31" \
    "\xf0\xb3\x8a\xf1\x57\x6f\x90\x1f\x3f\x74\x81\xb8" \
    "\x00\xb1\x9f\xcc\x8b\x10\x10\xbe\x62\xcd\x4a\x50" \
    "\x0e\x44\x4d\xb0\xfa\x47\x19\x78\xd9\xc6\xf4\xf7" \
    "\x9e\xa7\x10\xbd\x0a\x22\x39\xbf\x38\x0f\x90\x29" \
    "\x3b\x88\xfc\x19\xa1\xb4\xb2\x9c\xc1\xae\x6f\xfc" \
    "\x68\x6e\x71\x5c\x6b\xb2\x09\xcc\xdb\xf3\x5f\xdf" \
    "\xdc\x10\xb3\xdf\x39\x5a\x70\xa3\xbe\x60\x55\x71" \
    "\x43\x61\xa2\x24\x91\x1c\x18\xea\xf1\xec\xf4\x2d" \
    "\x88\x75\x2c\x56\xa8\x75\x13\x00\x7f\x01\x62\xd8" \
    "\x0d\x74\xed\x71\x61\xd8\x00\x00\x00\x00\x49\x45" \
    "\x4e\x44\xae\x42\x60\x82"

green_checkmark_image_data = \
    "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d" \
    "\x49\x48\x44\x52\x00\x00\x00\x10\x00\x00\x00\x10" \
    "\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\x00\x00\x01" \
    "\xac\x49\x44\x41\x54\x38\x8d\xc5\xd3\x3f\x48\x55" \
    "\x01\x14\xc7\xf1\xcf\xbd\xef\xbe\xe7\x43\x09\x85" \
    "\x47\x86\xa9\x39\xbc\x41\x08\x6a\x10\xca\x6a\x08" \
    "\x6c\x6f\xb3\xda\x42\x4a\xa4\x29\x82\xa0\x90\x96" \
    "\xa0\xa5\xcd\x96\x96\x1a\x84\xa2\xa5\x16\x03\xe1" \
    "\x35\x84\x5b\x42\xba\x54\xd0\x1f\xb0\xa0\x4c\x30" \
    "\x5e\x68\x2f\xcb\x7c\xff\xae\xb7\xa1\x40\x93\xb4" \
    "\xc1\xa1\xb3\x9c\xdf\x19\xbe\x1c\xf8\x9d\xdf\x09" \
    "\x92\x24\xb1\x9d\x0a\xb7\x45\x23\x30\xa2\x53\xdd" \
    "\x47\xcb\xf8\x81\x15\xd4\x11\x21\x83\xf4\x3a\x1d" \
    "\xfd\x9e\x33\xf2\x99\x06\x67\x53\x29\xfb\x22\xb1" \
    "\x87\xea\xae\xa0\xb0\xe5\xaa\x04\xab\x76\xe3\x8c" \
    "\xba\xa1\x6a\x5d\x39\x88\x9c\x08\xc3\x38\xac\xa5" \
    "\xb3\xe9\xbb\x6a\xfa\x36\x05\xab\x72\xb8\xdc\xd2" \
    "\xd1\x32\xd1\xd6\xd1\x76\xcd\x8a\x59\x15\xc7\xf0" \
    "\x3c\x4c\x96\x92\xfb\xb9\xbd\xb9\x5c\x76\x4f\xf6" \
    "\x8e\xb2\xc3\x82\x75\x70\xcd\x2e\xb1\x73\x51\x7b" \
    "\xf4\xa4\xfd\x78\xfb\xf5\xe6\xce\xe6\xee\xe2\x4c" \
    "\xb1\xa0\xe2\xa4\xc0\x1c\x44\x49\x29\x99\x5e\x2c" \
    "\x2f\x56\xc3\xfe\xb0\xc3\xa2\x7b\xde\xeb\xc7\x2b" \
    "\x55\x03\xba\x0c\x04\x47\x82\xde\xcc\x81\x8c\xd2" \
    "\xd3\x92\xe5\xc2\xf2\x03\x29\x43\xb2\x4a\x6b\x26" \
    "\x0e\x6a\xd5\xa5\xe0\x82\x1e\x45\x8c\x7a\x67\xc5" \
    "\x82\xa3\x0e\x3a\x84\x9d\x18\xc3\xb8\x1b\x1a\x5d" \
    "\xb5\xc3\x57\x19\x64\x09\x1a\x89\xac\x2a\x7a\x6b" \
    "\xca\x6b\x3d\xba\x71\x4a\x5e\x28\xaf\x0d\x35\xdc" \
    "\x54\x37\x65\x44\x83\x61\x29\xf1\x46\x8b\x42\x15" \
    "\x7c\x37\xed\x85\x58\x11\x0d\x68\xc2\x07\xdc\xc2" \
    "\x84\x61\x89\x4b\x7f\x83\x21\xf2\x0d\xb1\x49\xcf" \
    "\x2c\xd8\xaf\x55\x1a\x73\x18\x53\x36\xe3\xbc\x26" \
    "\xb7\xb7\x8a\x5b\x24\x46\xec\x8d\x39\x2f\x7d\xd2" \
    "\xaa\x8a\x71\x5f\xcc\xba\xa8\xd1\xe8\xbf\xb2\x1a" \
    "\xa9\x61\x15\x15\x13\x26\xf5\x99\xf7\xd9\xac\xd3" \
    "\x22\x8f\xfe\x38\xe9\x26\x95\x92\x47\x80\x44\xd9" \
    "\xbc\x5e\x4b\x06\x45\x1e\x0b\xac\x45\x77\x63\x4f" \
    "\xfd\xd2\x41\x9a\xe0\xbf\x7f\xe3\x4f\xae\x03\x8b" \
    "\xee\x04\xa5\xca\xcf\x00\x00\x00\x00\x49\x45\x4e" \
    "\x44\xae\x42\x60\x82"
########################################################################
#
# The group class
#
class group:
    def __init__(self, name = None, keysize = 0, password = None, imported = 0):
	self.name = name
	self.keysize = keysize
	self.password = password
	self.members = []
	self.num_members = 0
	self.imported = imported

    def add_member(self, member_name, member_host):
	self.members.append([member_name,member_host,0])
	self.num_members += 1


########################################################################
#
# The Add_Group dialog class
#
class Add_Group(QDialog):
    success = 0
    name = ""
    keysize = 0
    password = None

    def __init__(self,parent = None,name = None,modal = 0,fl = 0, font=None):
        QDialog.__init__(self,parent,name,modal,fl)

        if not name:
            self.setName("Add_Group")



        self.textLabel3_2_2 = QLabel(self,"textLabel3_2_2")
        self.textLabel3_2_2.setGeometry(QRect(11,100,50,21))
	self.textLabel3_2_2.setFont(font)

        self.textLabel3_2_3 = QLabel(self,"textLabel3_2_3")
        self.textLabel3_2_3.setGeometry(QRect(11,40,50,21))
	self.textLabel3_2_3.setFont(font)

        self.textLabel3_2 = QLabel(self,"textLabel3_2")
        self.textLabel3_2.setGeometry(QRect(11,70,50,21))
	self.textLabel3_2.setFont(font)

        self.textLabel3 = QLabel(self,"textLabel3")
        self.textLabel3.setGeometry(QRect(11,10,50,21))
	self.textLabel3.setFont(font)

        self.okButton = QPushButton(self,"okButton")
        self.okButton.setGeometry(QRect(230,130,61,21))
	self.okButton.setFont(font)

        self.confirmEdit = QLineEdit(self,"confirmEdit")
        self.confirmEdit.setGeometry(QRect(70,100,221,21))
	self.confirmEdit.setEchoMode(QLineEdit.Password)
	self.confirmEdit.setFont(font)

        self.passwordEdit = QLineEdit(self,"passwordEdit")
        self.passwordEdit.setGeometry(QRect(70,70,221,21))
	self.passwordEdit.setEchoMode(QLineEdit.Password)
	self.passwordEdit.setFont(font)

        self.keysizeComboBox = QComboBox(0,self,"keysizeComboBox")
        self.keysizeComboBox.setGeometry(QRect(70,40,71,21))
        self.keysizeComboBox.insertItem("2048", 0)
        self.keysizeComboBox.insertItem("1024", 1)
        self.keysizeComboBox.insertItem("512", 2)
        self.keysizeComboBox.setSizeLimit(3)
	self.keysizeComboBox.setFont(font)

        self.nameEdit = QLineEdit(self,"nameEdit")
        self.nameEdit.setGeometry(QRect(70,10,221,21))
	self.nameEdit.setFont(font)

        self.cancelButton = QPushButton(self,"cancelButton")
        self.cancelButton.setGeometry(QRect(160,130,61,21))
	self.cancelButton.setFont(font)

	self.setTabOrder(self.nameEdit, self.keysizeComboBox)
	self.setTabOrder(self.keysizeComboBox, self.passwordEdit)
	self.setTabOrder(self.passwordEdit, self.confirmEdit)
	self.setTabOrder(self.confirmEdit, self.okButton)
	self.setTabOrder(self.okButton, self.cancelButton)
	self.setTabOrder(self.cancelButton, self.nameEdit)
	self.nameEdit.setFocus()

        self.languageChange()

        self.resize(QSize(303,159).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

        self.connect(self.cancelButton,SIGNAL("clicked()"),self.close)
        self.connect(self.okButton,SIGNAL("clicked()"),self.do_ok)


    def verify_fields(self):
	if self.nameEdit.text().isEmpty():
	    crit_ok(self, "Error: Name is NULL.")
	    return 1

	if self.passwordEdit.text().isEmpty():
	    crit_ok(self, "Error: Password is NULL.")
	    return 1

	if self.passwordEdit.text().localeAwareCompare(self.confirmEdit.text()) != 0:
	    crit_ok(self, "Error: Passwords don't match!")
	    return 1

	return 0

    def do_ok(self):
	if (self.verify_fields() == 1):
	    return

	self.name = self.nameEdit.text().ascii()
	self.password = self.passwordEdit.text().ascii()
	self.keysize = self.keysizeComboBox.currentText().ascii()
	self.success = 1
	self.close()


    def languageChange(self):
        self.setCaption(self.__tr("Add Group..."))
        self.setIconText(QString.null)
        self.textLabel3_2_2.setText(self.__tr("<p align=\"right\">Confirm</p>"))
        self.textLabel3_2_3.setText(self.__tr("<p align=\"right\">Key Size</p>"))
        self.textLabel3_2.setText(self.__tr("<p align=\"right\">Password</p>"))
        self.textLabel3.setText(self.__tr("<p align=\"right\">Name</p>"))
        self.okButton.setText(self.__tr("&OK"))
        self.okButton.setAccel(self.__tr("Alt+O"))
        self.cancelButton.setText(self.__tr("&Cancel"))
        self.cancelButton.setAccel(self.__tr("Alt+C"))


    def __tr(self,s,c = None):
        return qApp.translate("Add_Group",s,c)

########################################################################
#
# The Add_Member dialog class
#
class Add_Member(QDialog):
    name = ""
    host = ""
    success = 0

    def __init__(self,parent = None,name = None,modal = 0,fl = 0,font=None):
        QDialog.__init__(self,parent,name,modal,fl)

        if not name:
            self.setName("Add_Member")

        self.textLabel3 = QLabel(self,"textLabel3")
        self.textLabel3.setGeometry(QRect(30,10,50,21))
	self.textLabel3.setFont(font)

        self.textLabel3_2 = QLabel(self,"textLabel3_2")
        self.textLabel3_2.setGeometry(QRect(30,40,50,21))
	self.textLabel3_2.setFont(font)

        self.okButton = QPushButton(self,"okButton")
        self.okButton.setGeometry(QRect(250,70,61,21))
	self.okButton.setFont(font)

        self.nameEdit = QLineEdit(self,"nameEdit")
        self.nameEdit.setGeometry(QRect(90,10,221,21))
	self.nameEdit.setFont(font)

        self.hostEdit = QLineEdit(self,"hostEdit")
        self.hostEdit.setGeometry(QRect(90,40,221,21))
	self.hostEdit.setFont(font)

        self.cancelButton = QPushButton(self,"cancelButton")
        self.cancelButton.setGeometry(QRect(180,70,61,21))
	self.cancelButton.setFont(font)

        self.languageChange()

        self.resize(QSize(320,99).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

	self.setTabOrder(self.nameEdit, self.hostEdit)
	self.setTabOrder(self.hostEdit, self.okButton)
	self.setTabOrder(self.okButton, self.cancelButton)
	self.setTabOrder(self.cancelButton, self.nameEdit)
	self.nameEdit.setFocus()

        self.connect(self.cancelButton,SIGNAL("clicked()"),self.close)
        self.connect(self.okButton,SIGNAL("clicked()"),self.do_ok)


    def confirm_text(self):
	if self.nameEdit.text().isEmpty():
	    warn_ok(self, "Error: Name is blank.")
	    return 1
	if self.hostEdit.text().isEmpty():
	    warn_ok(self, "Error: Host is blank.")
	    return 1

	return 0

    def do_ok(self):
	if (self.confirm_text() == 1):
	    return

	self.name = self.nameEdit.text().ascii()
	self.host = self.hostEdit.text().ascii()
	self.success = 1
	self.close()


    def languageChange(self):
        self.setCaption(self.__tr("Add Member..."))
        self.textLabel3.setText(self.__tr("<p align=\"right\">Name</p>"))
        self.textLabel3_2.setText(self.__tr("<p align=\"right\">Host</p>"))
        self.okButton.setText(self.__tr("&OK"))
        self.okButton.setAccel(self.__tr("Alt+O"))
        self.cancelButton.setText(self.__tr("&Cancel"))
        self.cancelButton.setAccel(self.__tr("Alt+C"))


    def __tr(self,s,c = None):
        return qApp.translate("Add_Member",s,c)
########################################################################
#
# The Main dialog class
#
class Main(QDialog):
    groups = []
    num_groups = 0
    save_path = ""

    def __init__(self,parent = None,name = None,modal = 0,fl = 0, num_groups = 0, groups = [], save_path = None):
        QDialog.__init__(self,parent,name,modal,fl)

        if not name:
            self.setName("Main")

        self.addmember_image = QPixmap()
        self.addmember_image.loadFromData(blue_play_image_data,"PNG")

        self.member_added_image = QPixmap()
        self.member_added_image.loadFromData(green_checkmark_image_data,"PNG")

        self.copy_paste_image = QPixmap()
        self.copy_paste_image.loadFromData(copy_image_data,"PNG")

        self.textLabel1 = QLabel(self,"textLabel1")
        self.textLabel1.setGeometry(QRect(30,40,231,21))

	self.font = QFont(self.textLabel1.font())
	self.font.setPointSize(CONFIG_FONT_SIZE)

        self.textLabel2 = QLabel(self,"textLabel2")
        self.textLabel2.setGeometry(QRect(30,0,331,41))

        self.addgroupButton = QPushButton(self,"addgroupButton")
        self.addgroupButton.setGeometry(QRect(270,60,90,21))

        self.importgroupButton = QPushButton(self,"importgroupButton")
        self.importgroupButton.setGeometry(QRect(270,90,90,21))

        self.delgroupButton = QPushButton(self,"delgroupButton")
        self.delgroupButton.setGeometry(QRect(270,120,90,21))

        self.addmemberButton = QPushButton(self,"addmemberButton")
        self.addmemberButton.setGeometry(QRect(270,150,90,21))

        self.delmemberButton = QPushButton(self,"delmemberButton")
        self.delmemberButton.setGeometry(QRect(270,180,90,21))

        self.groupComboBox = QComboBox(0,self,"groupComboBox")
        self.groupComboBox.setGeometry(QRect(30,60,230,20))

	self.memberTable = QTable(self, "memberTable")
	self.memberTable.setGeometry(QRect(30,90,230,200))
	self.memberTable.setNumCols(3)
	self.memberTable.setNumRows(0)
	self.memberTable.setReadOnly(1)

	self.memberTable.setFocusStyle(QTable.FollowStyle)
	self.memberTable.verticalHeader().hide()
	self.memberTable.setLeftMargin(0)
	self.memberTable.setShowGrid(0)
	self.memberTable.setSelectionMode(QTable.SingleRow)

	self.memberTable.horizontalHeader().setLabel(0,self.__tr(""))
	self.memberTable.horizontalHeader().setLabel(1,self.__tr("Name"))
	self.memberTable.horizontalHeader().setLabel(2,self.__tr("Host"))
	self.memberTable.setColumnStretchable(0,0)
	self.memberTable.setColumnStretchable(1,0)
	self.memberTable.setColumnStretchable(2,0)
	self.memberTable.setColumnWidth(0,16)

	self.qp = QPopupMenu()
	self.qp.insertItem(QIconSet(self.copy_paste_image), "Copy UUID", 0, 0)

        self.closeButton = QPushButton(self,"closeButton")
        self.closeButton.setGeometry(QRect(270,270,91,21))

        self.languageChange()

        self.resize(QSize(377,316).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

	self.setTabOrder(self.groupComboBox, self.addgroupButton)
	self.setTabOrder(self.addgroupButton, self.delgroupButton)
	self.setTabOrder(self.delgroupButton, self.importgroupButton)
	self.setTabOrder(self.importgroupButton, self.addmemberButton)
	self.setTabOrder(self.addmemberButton, self.delmemberButton)
	self.setTabOrder(self.delmemberButton, self.closeButton)
	self.setTabOrder(self.closeButton, self.memberTable)
	self.setTabOrder(self.memberTable, self.groupComboBox)
	self.addgroupButton.setFocus()

        self.connect(self.closeButton,SIGNAL("clicked()"),self.do_close)
	self.connect(self.addgroupButton,SIGNAL("clicked()"),self.show_add_group)
	self.connect(self.importgroupButton,SIGNAL("clicked()"),self.do_import_group)
	self.connect(self.addmemberButton,SIGNAL("clicked()"),self.show_add_member)
	self.connect(self.delgroupButton,SIGNAL("clicked()"),self.do_del_group)
	self.connect(self.delmemberButton,SIGNAL("clicked()"),self.show_delmember)
	self.connect(self.groupComboBox,SIGNAL("activated(int)"),self.change_group_selected)
	self.connect(self.memberTable,SIGNAL("clicked(int,int,int,const QPoint&)"),self.change_member_selected)
	self.connect(self.memberTable,SIGNAL("contextMenuRequested(int,int,const QPoint&)"),self.do_right_click)

	self.connect(self.qp,SIGNAL("activated(int)"), self.do_popup_selected)

	self.save_path = save_path
	self.groups = groups
	self.num_groups = num_groups

	if self.groups:
	    self.populate_group_box()
	    self.populate_table(0)
	else:
	    self.memberTable.setNumRows(0)
	    self.delmemberButton.setEnabled(0)
	    self.addmemberButton.setEnabled(0)
	    self.delgroupButton.setEnabled(0)


    # g() is basically a shorter way of typing self.groupComboBox.currentItem()
    def g(self):
	return self.groupComboBox.currentItem()


    def do_popup_selected(self, idx):
	try:
	    uuid = tpm_keyring_util_get_uuid(self.groups[self.g()].name)
	except IndexError:
	    return

	cb = QApplication.clipboard()
	cb.setText(uuid, QClipboard.Clipboard)
	if cb.supportsSelection():
	    cb.setText(uuid, QClipboard.Selection)


    def do_right_click(self, row, col, pos):
        if self.groups:
            self.qp.popup(pos)


    def do_about(self):
	QMessageBox.about(self, CONFIG_APP_STR, CONFIG_APP_STR + ": (C) 2006 Kent Yoder")


    def do_import_group(self):
	name_qstr, ok = QInputDialog.getText(CONFIG_APP_STR, "Enter the group's name:")

	if not ok:
	    return

	name = name_qstr.ascii()
	if self.name_exists(name):
	    crit_ok(self, "Group " + name + " already exists!")
	    return
        elif name == "":
	    crit_ok(self, "Please enter a group name to import")
	    return

	ret = tpm_keyring_util_import(name)
	if ret:
	    crit_ok(self, ret)
	    return

	uuid = tpm_keyring_util_get_uuid(name)
	keysize = tpm_keyring_util_get_keysize(name)

	self.groups.append(group(name, keysize, "", 1))
	self.groupComboBox.insertItem(self.__tr(name + " (" + str(keysize) + " bits, imported)"), \
				      self.num_groups)
	self.groupComboBox.setCurrentItem(self.num_groups)
	self.num_groups += 1

	self.groups[self.g()].add_member("me", uuid)
	self.groups[self.g()].num_members = 1
	self.groups[self.g()].members[0][2] = 1
	self.change_group_selected(self.g())


    def do_del_group(self):
	name = self.groups[self.g()].name
	ans = q_yesno(self, "Are you sure you want to remove group \"" + name + \
                      "\" and all its members?")
	if ans == QMessageBox.Yes or ans == 0:
	    if self.groups[self.g()].imported == 0:
	        ret = tpm_keyring_util_remove_swkey(name, self.save_path)
	        if ret:
		    warn_ok(self, ret)

            ret = tpm_keyring_util_unregister_local(name)
	    if ret:
	        warn_ok(self, ret)

	    del self.groups[self.g()]
	    self.num_groups -= 1
	    self.groupComboBox.removeItem(self.g())
	    self.populate_table(self.g())


    def name_exists(self, name):
	i = 0
	while i < self.num_groups:
	    if (self.groups[i].name == name):
		return 1
	    i += 1

	return 0


    def do_close(self):
	i = 0
	while i < self.num_groups:
	    self.groups[i].password = None
	    i += 1

	self.close()


    def populate_table(self, grp_idx):
	try:
	    self.memberTable.setNumRows(self.groups[grp_idx].num_members)
	except IndexError:
	    self.memberTable.setNumRows(0)
	    return

	i = 0
	while i < self.groups[grp_idx].num_members:
	    if self.groups[self.g()].imported == 1:
	        self.memberTable.setText(i, 1, self.groups[grp_idx].members[i][0])
	        self.memberTable.setText(i, 2, self.groups[grp_idx].members[i][1])
	    else:
	        self.memberTable.setText(i, 1, self.groups[grp_idx].members[i][0])
	        self.memberTable.setText(i, 2, self.groups[grp_idx].members[i][1])

	    if (self.groups[grp_idx].members[i][2] == 0):
		self.memberTable.setPixmap(i, 0, self.addmember_image)
	    else:
		self.memberTable.setPixmap(i, 0, self.member_added_image)

	    i += 1

	if self.groups[self.g()].imported == 1:
	    self.addmemberButton.setEnabled(0)
	    self.delmemberButton.setEnabled(0)
	    self.memberTable.horizontalHeader().setLabel(2,self.__tr("UUID"))
	    self.memberTable.setColumnWidth(0,16)
	    self.memberTable.setColumnWidth(1,45)
	    self.memberTable.setColumnWidth(2,165)
	else:
	    self.addmemberButton.setEnabled(1)
	    self.delmemberButton.setEnabled(1)
	    self.memberTable.horizontalHeader().setLabel(2,self.__tr("Host"))
	    self.memberTable.setColumnWidth(0,16)
	    self.memberTable.setColumnWidth(1,60)
	    self.memberTable.setColumnWidth(2,145)


    def populate_group_box(self):
	i = 0
	while i < self.num_groups:
	    if self.groups[i].imported == 1:
	        self.groupComboBox.insertItem(self.__tr(self.groups[i].name + " (" + \
					      str(self.groups[i].keysize) + " bits, imported)"), i)
	    else:
	        self.groupComboBox.insertItem(self.__tr(self.groups[i].name + " (" + \
					      str(self.groups[i].keysize) + " bits)"), i)
	    i += 1


    def change_group_selected(self, idx):
	if not self.groups:
	    self.memberTable.setNumRows(0)
	    self.delmemberButton.setEnabled(0)
	    self.addmemberButton.setEnabled(0)
	    self.delgroupButton.setEnabled(0)
	    return
        else:
	    self.delgroupButton.setEnabled(1)

	self.populate_table(idx)


    def show_send_key(self, row):
	group = self.groups[self.g()].name
	name = self.groups[self.g()].members[row][0]
	host = self.groups[self.g()].members[row][1]

	# If the sw key password is None, it hasn't yet been entered in this session
        if self.groups[self.g()].password == None:
            qsw_pass, ok = QInputDialog.getText(CONFIG_APP_STR,
			                        "Enter the software key password for group \"" \
                                                + group + "\":", QLineEdit.Password)
	    if not ok:
	        crit_ok(self, "Sending key to " + name + "cancelled.")
	        return

	    self.groups[self.g()].password = qsw_pass.ascii()

	ctx = tpm_keyring_util_create_ctx(0, group, self.groups[self.g()].password, host, \
				          self.save_path)
	if not ctx:
	    crit_ok(self, "Error creating context with helper library.")
	    return

	ret = tpm_keyring_util_send_key(ctx);

	# If send_key asks us to prompt for a new software key, do, looping until we get it right
	while ret == "swprompt":
            qsw_pass, ok = QInputDialog.getText(CONFIG_APP_STR,
			                        "Enter the software key password for group \"" \
                                                + group + "\":", QLineEdit.Password)
	    if not ok:
	        crit_ok(self, "Sending key to " + name + "cancelled.")
	        return

	    self.groups[self.g()].password = qsw_pass.ascii()

            ctx = tpm_keyring_util_create_ctx(0, group, self.groups[self.g()].password, host, \
				              self.save_path)
	    if not ctx:
	        crit_ok(self, "Error creating context with helper library.")
	        return

	    ret = tpm_keyring_util_send_key(ctx);

	# Now loop until we get the SRK password correct
        while ret == "prompt":
	    qsrk_pass, ok = QInputDialog.getText(CONFIG_APP_STR, \
					         "Enter the SRK password:", QLineEdit.Password)
	    if not ok:
	        tpm_keyring_util_remove_swkey(name, self.save_path)
	        tpm_keyring_util_ctx_close(ctx)
	        crit_ok(self, "Sending key to " + name + "cancelled.")
	        return

	    srkpass = qsrk_pass.ascii()

	    ret = tpm_keyring_util_send_key_retry(ctx, srkpass)

        if ret == "nosrk":
	    crit_ok(self, "It appears that the TPM on " + host + \
		    " hasn't had an owner set yet. Aborting.")
	    tpm_keyring_util_remove_swkey(name, self.save_path)
	    tpm_keyring_util_ctx_close(ctx)
	    return

	if ret:
	    crit_ok(self, ret)
	    tpm_keyring_util_remove_swkey(name, self.save_path)
	    tpm_keyring_util_ctx_close(ctx)
	    return

	tpm_keyring_util_ctx_close(ctx)

	self.groups[self.g()].members[row][2] = 1
	self.memberTable.setPixmap(row, 0, self.member_added_image)


    def change_member_selected(self, row, col, button, mouse_pos):
	try:
	    if self.groups[self.g()].members[row]:
		if self.groups[self.g()].members[row][2] == 0:
		    self.delmemberButton.setEnabled(1)
		    if col == 0:
			self.show_send_key(row)
	except IndexError:
	    pass


    def show_add_group(self):
	ag = Add_Group(None,None,0,0,self.font)
	ag.show()
	ag.exec_loop()

	if ag.success:
	    name, keysize, password = ag.name, ag.keysize, ag.password

	    if (self.name_exists(name)):
		crit_ok(self, "Error, group " + name + " already exists")
		return

	    ctx = tpm_keyring_util_create_ctx(int(keysize), name, password, "", self.save_path)
	    if not ctx:
	        crit_ok(self, "Error creating context.")
	        return

	    ret = tpm_keyring_util_create_group(ctx)
	    while ret == "prompt":
	        qsrk_pass, ok = QInputDialog.getText(CONFIG_APP_STR, \
						     "Enter the local SRK password:", \
						     QLineEdit.Password)
	        if not ok:
		    tpm_keyring_util_remove_swkey(name, self.save_path)
		    tpm_keyring_util_ctx_close(ctx)
		    return

	        strpass = qsrk_pass.ascii()
	        ret = tpm_keyring_util_create_group_retry(ctx, strpass)

            if ret == "nosrk":
	        crit_ok(self, "It appears that your TPM hasn't had an owner set yet.\n" + \
			" Please take ownership of your TPM and try again.")
		tpm_keyring_util_remove_swkey(name, self.save_path)
	        tpm_keyring_util_ctx_close(ctx)
	        return

	    if ret:
	        crit_ok(self, ret)
		tpm_keyring_util_remove_swkey(name, self.save_path)
	        tpm_keyring_util_ctx_close(ctx)
	        return

	    tpm_keyring_util_ctx_close(ctx)

	    #if not password:
	    #    warn_ok(self, "Warning: Using no password for the software key for group \"" \
            #             + name + "\"")

	    self.groups.append(group(name, keysize, password))
	    self.groupComboBox.insertItem(self.__tr(name + " (" + str(keysize) + " bits)"), \
					  self.num_groups)
	    self.num_groups += 1
	    self.addmemberButton.setEnabled(1)

	    self.groupComboBox.setCurrentItem(self.num_groups - 1)
	    self.change_group_selected(self.num_groups - 1)


    def show_add_member(self):
	am = Add_Member(None,None,0,0,self.font)
	am.show()
	am.exec_loop()

	if am.success:
	    name, host = am.name, am.host
	    self.groups[self.g()].add_member(name, host)
	    row_idx = self.groups[self.g()].num_members - 1
	    self.memberTable.setNumRows(self.groups[self.g()].num_members)
	    self.memberTable.setText(row_idx, 1, self.groups[self.g()].members[row_idx][0])
	    self.memberTable.setText(row_idx, 2, self.groups[self.g()].members[row_idx][1])
	    self.memberTable.setPixmap(row_idx, 0, self.addmember_image)


    def show_delmember(self):
	m = self.memberTable.currentRow()
	if not self.memberTable.isRowSelected(m):
	    crit_ok(self, "Please select a member to delete!")
	    return

	member = self.groups[self.g()].members[m][0]
	group = self.groups[self.g()].name
	ans = q_yesno(self, "Are you sure you want to delete \"" + member + "\" from group " + \
                      group + "?")
	if ans == QMessageBox.Yes or ans == 0:
	    del self.groups[self.g()].members[m]
	    self.groups[self.g()].num_members -= 1
	    self.memberTable.removeRow(m)
	    self.memberTable.clearSelection()


    def languageChange(self):
        self.setCaption(self.__tr("TPM keyring"))
        self.textLabel2.setText(self.__tr("<font face=\"Sandoval\"><h1><p align=\"center\">TPM KeyRing</p></h1></font>"))

        self.textLabel1.setText(self.__tr("<b>Group</b>"))
	self.textLabel1.setFont(self.font)

        self.delmemberButton.setText(self.__tr("Delete Member..."))
	self.delmemberButton.setFont(self.font)

	self.addmemberButton.setText(self.__tr("Add &Member..."))
        self.addmemberButton.setAccel(self.__tr("Alt+M"))
	self.addmemberButton.setFont(self.font)

        self.addgroupButton.setText(self.__tr("Add &Group..."))
        self.addgroupButton.setAccel(self.__tr("Alt+G"))
	self.addgroupButton.setFont(self.font)

	self.importgroupButton.setText(self.__tr("Import Group..."))
	self.importgroupButton.setFont(self.font)

	self.delgroupButton.setText(self.__tr("Delete Group..."))
	self.delgroupButton.setFont(self.font)

        self.closeButton.setText(self.__tr("&Close"))
        self.closeButton.setAccel(self.__tr("Alt+C"))
	self.closeButton.setFont(self.font)

	self.memberTable.setFont(self.font)
	self.groupComboBox.setFont(self.font)


    def clicked(self):
        print "Main.clicked(): Not implemented yet"


    def __tr(self,s,c = None):
        return qApp.translate("Main",s,c)


########################################################################
#
# Utility functions
#
def save_data(num_groups, groups, save_path):
    # Save group data if it exists
    if not save_path:
        print "Not saving data."
        return

    if not groups:
        try:
	    posix.unlink(save_path + CONFIG_DATA_PATH)
        except:
	    pass

        return

    try:
        f = open(save_path + CONFIG_DATA_PATH, 'w+', CONFIG_DATA_MODE)

        try:
	    cPickle.dump([num_groups, groups], f)
        finally:
	    f.close()

    except IOError:
        pass


def load_data():
    num_groups = 0
    groups = []

    if SAVE_PATH:
        path = SAVE_PATH
    else:
        euid = posix.geteuid()
        pwent = pwd.getpwuid(euid)

        path = pwent.pw_dir

    if not path:
        print "Error getting save location! Data will not be saved!"
        return

    save_path = path + SAVE_DIR
    # Make sure the dir exists first
    if not os.path.isdir(save_path):
        try:
            os.mkdir(save_path, SAVE_PATH_MODE)
        except OSError, err:
	    if err.errno == errno.EEXIST:
	        if not os.path.isdir(save_path):
		    print "Save path " + save_path + " exists, but is not a directory! Exiting!"
		    return -1, 0, 0
	    else:
		print "Error creating save dir: " + save_path + ". Exiting!"
		return -1, 0, 0

    # Read in the saved data if it exists
    try:
        f = open(save_path + CONFIG_DATA_PATH, 'r')

        try:
            num_groups, groups = cPickle.load(f)
	finally:
	    f.close()

    except EOFError:
	pass
    except IOError:
	pass

    # Set the environment variable to point the TSS to our save_path
    try:
        posix.putenv("TSS_USER_PS_FILE", save_path + CONFIG_TSS_KEYSTORE_PATH)
    except:
        print "Error setting TSS key store environment variable:", \
              save_path + CONFIG_TSS_KEYSTORE_PATH
	return -1, 0, 0

    return num_groups, groups, save_path


def warn_ok(parent, str):
    QMessageBox.warning(parent, CONFIG_APP_STR, str, QMessageBox.Ok, QMessageBox.NoButton)


def crit_ok(parent, str):
    QMessageBox.critical(parent, CONFIG_APP_STR, str, QMessageBox.Ok, QMessageBox.NoButton)


def q_yesno(parent, str):
    return QMessageBox.question(parent, CONFIG_APP_STR, str, QMessageBox.Yes, QMessageBox.No)


########################################################################
#
# Main
#
if __name__ == "__main__":
    num_groups, groups, save_path = load_data()

    if num_groups == -1:
	sys.exit(-1)

    app = QApplication(sys.argv)
    m = Main(None, None, 0, 0, num_groups, groups, save_path)
    m.show()
    app.setMainWidget(m)
    app.exec_loop()

    save_data(m.num_groups, m.groups, save_path)

