#!/usr/bin/python
# *-* coding:utf-8 *-*

#***************************************************************************
# This file is part of the CRYPTO BONE
# File     : cryptobone  installed in /usr/bin
# Version  : 1.0.5 (ALL-IN-ONE)
# License  : BSD
# Date     : Tuesday, 2 August 2016
# Contact  : Please send enquiries and bug-reports to innovation@senderek.ie
#
#
# Copyright (c) 2015-2016
#	Ralf Senderek, Ireland.  All rights reserved. (https://senderek.ie)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#	   This product includes software developed by Ralf Senderek.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND  ANY EXPRESS OR 
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  IMPLIED WARRANTIES 
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
#****************************************************************************

import os
import base64
import time

# debugging off
DEBUG_DISPLAY = False
DEBUG = False

# debugging on
#DEBUG = True
#DEBUG_DISPLAY = True

OS = os.name

# find out askpass path
ASKPASSS = "/usr/bin/systemd-ask-password"
if os.path.isfile ("/usr/libexec/openssh/gnome-ssh-askpass"):
     ASKPASS="/usr/libexec/openssh/gnome-ssh-askpass"
else:
     if os.path.isfile ("/usr/lib64/seahorse/seahorse-ssh-askpass"):
          ASKPASS="/usr/lib64/seahorse/seahorse-ssh-askpass"
     else:
          if os.path.isfile("/usr/lib/openssh/gnome-ssh-askpass"):
               ASKPASS = "/usr/lib/openssh/gnome-ssh-askpass"

	 

GUI = False
try:
    from Tkinter import *
    from tkMessageBox import *
    import tkFont
    GUI = True
except:
    pass

RAMDISK = "/dev/shm"

Name="none"
StatusCount=10
MaxCount=0
Masterkey = False
Power = True
MODE = "read"
Allinone = True
MessageID = "None"
Recipient = "None"

###############################################################
def unix (command) :
     if OS == "posix":
          Pipe = os.popen(command, "r")
          Result = Pipe.read()
          Pipe.close()
     return Result

###############################################################
def clean ():
     Text.delete("0.0","end")


###############################################################
def is_active():
     Result = send_command("STATUS")
     if Result[:6] == "active":
          return True
     return False	  

###############################################################
def check_status():
     global Allinone, Name, StatusCount, MaxCount

     if StatusCount > MaxCount:
          StatusCount = 0
          Result = send_command("STATUS")
     else:
          Result = "none"
     StatusCount += 1
     if  "waiting" in Result:
          StatusLabel.configure(text="waiting")
	  StatusLabel.configure(bg="orange")
     if  "offline" in Result:
          StatusLabel.configure(text="cut off")
	  StatusLabel.configure(bg="yellow")
	  showinfo("EXTERNAL Crypto Bone is inactive","Your EXTERNAL Crypto Bone is offline.\nPlease switch it on or check its network connection.\n")
     if "active" in Result:
          MaxCount=10
          StatusLabel.configure(text="active")
	  StatusLabel.configure(bg="lightgreen")
	  if Name == "none":
               Result = send_command("SETUP ID")
               if not "failed" in Result:
                    ID.configure(text=Result[:-1])
		    Name=Result[:-1]
     else:
          MaxCount = 0
     if "master key not available" in Result:
          StatusLabel.configure(text="inactive")
	  StatusLabel.configure(bg="yellow")
	  showinfo("EXTERNAL Crypto Bone is inactive","You need to reboot your computer while the EXTERNAL Crypto Bone is running to transfer the master key.\n")
     if "boneless" in Result:
          StatusLabel.configure(text="cut off")
	  StatusLabel.configure(bg="yellow")
	  showinfo("EXTERNAL Crypto Bone is inactive","The IP address of your EXTERNAL Crypto Bone is unknown.\n")
     if "ssh key not available" in Result:
          StatusLabel.configure(text="cut off")
	  StatusLabel.configure(bg="yellow")
	  showinfo("EXTERNAL Crypto Bone is inactive","You need to store your EXTERNAL keys in your computer first. Please use setup to copy these keys.\n")
	
     Linkstatus = send_command("GETALLINONE")
     if "ALLINONE" in Linkstatus :
          Allinone = True
	  IPLabel.configure(text="ALL-IN-ONE")
     else:
          Allinone = False
	  IPLabel.configure(text=Linkstatus)

###############################################################
def contact():
     import subprocess

     Content = InputField.get().split(" ")
     args = ["sudo", "-A", "/usr/lib/cryptobone/cbcontrol"]
     for Word in Content:
          args.append(Word)
     ENV = os.environ.copy()	  
     ENV['SUDO_ASKPASS'] =  ASKPASS
     p = subprocess.Popen(args, bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False, env=ENV)
     if DEBUG_DISPLAY:
          print InputField.get()
     (out,err) =  p.communicate()
     if err != None:
          print "error:",str(err)
     if DEBUG_DISPLAY:	   
          Text.insert("end",str(out))
          Text.insert("end", "\n")

###############################################################
def send_command(Command):
     import subprocess

     # sanitize input
     Input = ""
     for C in Command:
          if (ord(C) > 0) and (ord(C) < 128):
	       Input += C
     Content = Input.split(" ")	       
     args = ["sudo", "-A", "/usr/lib/cryptobone/cbcontrol"]
     for Word in Content:
          args.append(Word)
     ENV = os.environ.copy()	  
     ENV['SUDO_ASKPASS'] =  ASKPASS
     p = subprocess.Popen(args, bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False, env=ENV)
     if DEBUG_DISPLAY:
          print Input
     (out,err) =  p.communicate()
     if err != None:
           print "error:",str(err)
     if DEBUG_DISPLAY:	   
           Text.insert("end",str(out))
           Text.insert("end", "\n")
     return str(out)

###############################################################
def set_select_box():
     List = []
     if MODE == "write":
	  List = send_command("KEY RECIPIENTLIST").split("\n")
     if MODE == "read":
	  List = send_command("READ MESSAGELIST").split("\n")
     Box.delete(0,20)   
     Count = 0
     for Item in List:
          if Item :
               Box.insert(Count, str(Item))
          Count += 1


###############################################################
def set_read():
     global MODE, MessageID
     MODE = "read"
     Mode.configure(text="READ")
     L.configure(text="Messages")
     ControlFrame.pack_forget()
     Key1.pack_forget()
     Key2.pack_forget()
     Key3.pack_forget()
     Setup1.pack_forget()
     clean()
     TextFrame.pack()
     ControlFrame.pack()
     Button1.configure(text="Reply")
     Button2.configure(text="Check for new")
     Button3.configure(text="Destroy")
     Fill.pack_forget()
     Button2.pack(padx=20, side=LEFT)
     Button3.pack(padx=20, side=RIGHT)
     set_select_box()
     SelectBox.pack()
     MessageID = "None"
     L1.configure(text=MessageID)
     L2.configure(text="NEW")
     check_status()

###############################################################
def set_write():
     global MODE, Recipient
     MODE = "write"
     Mode.configure(text="WRITE")
     L.configure(text="Recipients")
     ControlFrame.pack_forget()
     Key1.pack_forget()
     Key2.pack_forget()
     Key3.pack_forget()
     Setup1.pack_forget()
     clean()
     TextFrame.pack()
     ControlFrame.pack()
     Button1.configure(text="Send Message")
     Button2.configure(text="Forget")
     Button2.pack(padx=20, side=LEFT)
     Fill.pack_forget()
     Button3.pack_forget()
     set_select_box()
     SelectBox.pack()
     Recipient = "None"
     L1.configure(text=Recipient)
     L2.configure(text="NEW")
     check_status()

###############################################################
def set_reply():
     global MODE
     MODE = "write"
     Mode.configure(text="WRITE")
     ControlFrame.pack_forget()
     Key1.pack_forget()
     Key2.pack_forget()
     Key3.pack_forget()
     Setup1.pack_forget()
     clean()
     TextFrame.pack()
     ControlFrame.pack()
     Button1.configure(text="Send Message")
     Button2.configure(text="Forget")
     Fill.pack_forget()
     Button3.pack_forget()
     SelectBox.pack_forget()
     L1.configure(text="Recipient")
     L2.configure(text="REPLY")

###############################################################
def set_key():
     global MODE
     MODE = "key"
     Mode.configure(text="KEYS")
     SelectBox.pack_forget()
     TextFrame.pack_forget()
     ControlFrame.pack_forget()
     Setup1.pack_forget()
     Key1.pack()
     Key2.pack()
     Key3.pack()
     L1.configure(text="")
     L2.configure(text="")
     check_status()

###############################################################
def set_setup():
     global MODE, Allinone
     MODE = "setup"
     Mode.configure(text="SETUP")
     SelectBox.pack_forget()
     TextFrame.pack_forget()
     ControlFrame.pack_forget()
     Key1.pack_forget()
     Key2.pack_forget()
     Key3.pack_forget()
     Setup1.pack()
     ControlFrame.pack()
     Linkstatus = send_command("GETALLINONE")
     if "ALLINONE" in Linkstatus :
          Button1.configure(text="Use EXTERNAL Bone")
          Button2.pack_forget()
     else:
          Button1.configure(text="Use ALL-IN-ONE")
          Button2.configure(text="Setup EXTERNAL Keys")
	  Button2.pack()
     Button3.pack_forget()
     L1.configure(text="")
     L2.configure(text="")

###############################################################
def action1():
    global Recipient, MessageID, Allinone, PoweroffButton, Fill2, Name, StatusCount
    if MODE == "read":
         # reply to the selected message
	 MESSAGE = Text.get("0.0","end").split("\n")
         
	 set_reply()
	 Text.insert("end","\n\n\n")
	 for Line in MESSAGE:
	      if Line:
	           Text.insert("end", "> "+Line+"\n")
	 if len(MessageID) > 4 :
	       while MessageID[len(MessageID)-1] != '.':
	            MessageID = MessageID[:-1]
               Recipient = MessageID[:-1]		   
	 L1.configure(text=Recipient)     
	 L2.configure(text="REPLY")     

    elif MODE == "write":
	 MESSAGE = Text.get("0.0","end")
	 # sanitize message
	 NEWMESSAGE = ""
	 for C in MESSAGE:
	      if ord(C) <= 128:
	          NEWMESSAGE += C
	 MESSAGE = base64.b64encode(NEWMESSAGE)
	 if Recipient != "None":
	      Result = send_command("WRITE "+Recipient+" "+MESSAGE)
	      if ("MAIL SENT" in Result) or ("sending message" in Result) :
	           Text.insert("end", "\n\n"+Result)
	           showinfo("Sending Message Out","Message is sent out successfully")
	      else:	   
	           showinfo("Sending Message Out","Message is not sent out!")
	 else:     
	      showinfo("Missing Information","Please select a recipient from the menu before sending the message")

    elif MODE == "key":
        print "action one key"

    elif MODE == "setup":
        if Power:
             if not Allinone:
                  Allinone = True
                  Button1.configure(text="Use EXTERNAL Bone")
                  IPLabel.configure(text="ALL-IN-ONE")
	          send_command("USEALLINONE")
                  PoweroffButton.pack_forget()
		  Fill2.pack(pady=5)
             else:
                  Allinone = False
                  Button1.configure(text="Use ALL-IN-ONE")
                  IPLabel.configure(text="EXTERNAL Crypto Bone")
	          send_command("USECRYPTOBONE")
		  Fill2.pack_forget()
                  PoweroffButton.pack(pady=7) 
             StatusCount = 100
	     Name = "none"
             ID.configure(text="")
	     set_setup()		  
             check_status()

###############################################################
def action2():
    global Recipient, MessageID

    if MODE == "read":
         # check for new messages
         set_select_box()


    elif MODE == "write":
         # forget message
	 MessageID = "none"
	 Recipient = "Recipient"
	 L1.configure(text=Recipient)
	 L2.configure(text="NEW")
	 clean()
         set_select_box()
	 SelectBox.pack()

    elif MODE == "key":
         print "action two key"
   
    elif MODE == "setup":
	 List = unix("df 2> /dev/null | cut -f1 -d' '| grep /dev").split()
	 Target = ""
	 count = 0
	 BootDev = ""
	 SD = False
         for Device in List:
	      BootDir = unix("df -a 2> /dev/null | grep media | grep BOOT | cut -f1 -d' '") 
	      if BootDir:
	           BootDev = unix("df -a 2> /dev/null | grep media | grep BOOT | cut -f1 -d' '")
	           if BootDev[-1:] == "\n":
	                BootDev = BootDev[:-1]
	           SD = True
              else:
	           if Device == "/dev/sdb1":
	  	        Target = "/dev/sdb1"
		        count += 1
		       
	           if Device == "/dev/sdc1":
		        Target = "/dev/sdc1"
		        count += 1
		       
	           if Device == "/dev/sdd1":
		        Target = "/dev/sdd1"
		        count += 1
         if SD:
              print "Copying keys from "+BootDev+" to the computer's hard disk"      
	      if askyesno("Moving Keys From SD Card or USB stick","Copying keys from "+BootDev+" to the computer's hard disk\n\nProceed?"):
	           if askyesno("Moving Keys From SD Card or USB stick","You will now replace the keys that are used to access your EXTERNAL Crypto Bone.\n\nIf your EXTERNAL Crypto Bone is already working, you will DESTROY the keys used to access this working EXTERNAL Crypto Bone by replacing the old keys with new keys from the SD card or USB stick.\n\nOnce you have replaced the external keys, this action cannot be undone. You will continue with a new EXTERNAL Crypto Bone, if you proceed here.\n\nDo your really want to do that?\n\nThink twice."):
                        RES = send_command("COPYSDCARD "+BootDev)
		        if "success" in RES :
		             showinfo("Moving Keys From EXTERNAL Memory","Your Crypto Bone keys have been moved successfully to your computer.\n\nNow you can insert the SD card into your Beagle Bone or Raspberry Pi again and reboot it.\n\nYou need to reboot your computer as well in order to activate the new keys.")
		        elif "failed" in RES :
                             showinfo("Moving Keys From EXTERNAL Memory","There are no keys on your SD card!\n\nCheck your SD card image and insert it for a first boot into your Crypto Bone or Crypto Pi.")

	 else:
                        showinfo("Moving Keys From EXTERNAL Memory","There is no SD card with a valid Crypto Bone image or a valid USB stick.")


###############################################################
def action3():
    if MODE == "read":
         # destroy selected message
	 if askyesno("Destroy Message", "Do you really want to destroy this message: "+MessageID):
              send_command("READ DESTROY "+MessageID)
              clean()
              set_select_box()


###############################################################
def select():
    global MessageID, Recipient

    index = 0
    if len(Box.curselection()) > 0:
         index = Box.curselection()[0]
    Selection = Box.get(index)
    L1.configure(text=Selection)
    if MODE == "read":
        MessageID = Selection
	MESSAGE = send_command("READ MESSAGE "+MessageID)
	if MESSAGE:
	     clean()
	     Plaintext = base64.b64decode(MESSAGE)
	     NewPlaintext = Plaintext.replace("\r","")
	     Text.insert("end",NewPlaintext)

	     
    elif MODE == "write":
        Recipient = Selection


###############################################################
def is_message_key(NewKey):
     if NewKey == "none":
          return False
     if len(NewKey) > 19:
          return True
     return False

###############################################################
def register():
     if not is_active():
         return "failed"
     K = InitKey.get()
     E = Email.get().lower()
     if is_message_key(K):
          # todo: check if email address is stored already
          RES = send_command("KEY USE "+E+" "+K)
	  if "failed" in RES :
	       showerror('Contact Registration', RES[8:])
	  if "success" in RES :     
	       showinfo('Contact Registration', E + "\n\nis now registered and can be used.")
     else:
          showerror('Contact Registration', "The message key is too short.")
         

###############################################################
def change_email():
    if not is_active():
        return "failed"
    Name =  OldName.get()
    Email = OldEmail.get()
    Email = Email.lower()
    New = NewEmail.get()
    New = New.lower()
    if not (Name == "Contact Email Address"):
         Email = Name
    if (Email != "" ) and (New != "") :	 
         RES = send_command("KEY CHANGEEMAIL "+Email+" "+New)
         print RES
	 if "success" in RES :
              showinfo('Email Address Change', 'The new email address is now active.')
	 else:
	      if "failed" in RES :
                    showinfo('Email Address Change', RES[8:])
    else:
         if (len(Email) < 6):
	      if (Name == "Contact Email Address"):
                   showerror('Email Address Change', "The email address is invalid.")
	 else:
	      if (len(New) < 6):
                   showerror('Email Address Change', "The new email address is invalid.")


###############################################################
def print_secrets():

     if is_active():     
          RES = send_command("KEY NEWSECRETS")
          Message = "These are three keys that can be used by your contacts\n\n"
          Keys = RES.split()
          for Line in Keys:
                List = Line.split(":")
	        if len(List) > 1:
	              Message += "________________________________\n\n"
	              Message += "Initial key for " +List[0][4:-4] + " :\n"
	              Message += List[1] + "\n"
          Message += "________________________________\n\n"
          Message += "\n\nPlease handle this information with extreme care!"
          askokcancel("New Secrets for Contacts", Message)



###############################################################
def show_mailserver_setup():
     Result = send_command("SETUP SHOW")
     if Result:
          List = Result.split("\n")
	  for Line in List:
	       Secretvalue = Line.split(":")
	       if Secretvalue[0] == "mailserver":
                    Hostname.delete(0,END)		       
                    Hostname.insert(0,Secretvalue[1])		       
	       if Secretvalue[0] == "mailuser":
                    Username.delete(0,END)		       
                    Username.insert(0,Secretvalue[1])		       
	       if Secretvalue[0] == "mailpassword":
                    Password.delete(0,END)		       
                    Password.insert(0,Secretvalue[1])		       

###############################################################
def mailserver_setup():
    H = Hostname.get()
    U = Username.get()
    P = Password.get()
    if H :
         send_command("SETUP SERVER "+H)
    if U :
         send_command("SETUP USER "+U)
    if P :
         send_command("SETUP PASSWORD "+P)

###############################################################
def terminate_GUI():
     Window.destroy()     

###############################################################
def do_poweroff():

     if not "ALLINONE" in send_command("GETALLINONE"):     
          X=send_command("POWEROFF")
          print X
          check_status()

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


###############################################################
# Main
###############################################################

if GUI:

     Window = Tk()
     Window.title("Crypto Bone Control")
     Window.geometry('900x550')

     StatusFrame = Frame(Window, pady=5)
     MainFrame = Frame(Window)
     LeftFrame = Frame(MainFrame, pady=2)
     ModeFrame = Frame(LeftFrame, pady=5)
     TopFrame = Frame(LeftFrame, pady=10)
     TextFrame = Frame(LeftFrame)
     ControlFrame = Frame(LeftFrame, pady=5)
     RightFrame = Frame(MainFrame, pady=2)
     BottomFrame = Frame(Window, pady=5)
     

     Big = tkFont.Font(family="utopia", size=16)
     Title = tkFont.Font(family="utopia", size=12)
     Info = tkFont.Font(family="Arial", size=10, slant="italic")
     Bold = tkFont.Font(family="Arial", size=10, weight="bold")

     # DEBUG frame
     if DEBUG:
          ButtonFrame = Frame(Window)
          CleanButton = Button(master=ButtonFrame, text="Clean", command=clean)
          InputField = Entry(master=ButtonFrame, width=40) 
          ExecButton = Button(master=ButtonFrame, text="do it!", command=contact)
          CleanButton.pack(side=LEFT) 
          InputField.pack(padx=20,side=LEFT) 
          ExecButton.pack(side=LEFT) 
          ButtonFrame.pack()

     def OpenHelpUrl():
          import webbrowser
          webbrowser.open_new("https://crypto-bone.com/help")
     
     # Status
     BoneLabel = Label(StatusFrame, text="CRYPTO BONE  1.0", font=Big, height=1, width=28)
     BoneLabel.bind("<Button-1>",lambda e: OpenHelpUrl())
     IPLabel = Label(StatusFrame, text="", width=20,  bg="#eeffee")
     StatusLabel = Label(StatusFrame, text="cut off", width=12, bg="yellow")
     Space = Label(StatusFrame, text="", width=4)
     ID = Label(StatusFrame, text="", font=Bold, width=30, bg="#eeffee")
     BoneLabel.pack(side=LEFT)
     IPLabel.pack(side=LEFT, fill=Y)
     StatusLabel.pack(side=LEFT, fill=Y)
     Space.pack(side=LEFT)
     ID.pack(side=RIGHT)


     # Labels
     Mode = Label(TopFrame, text="READ", bg="yellow", width=10)
     L1 = Label(TopFrame, text="None", width=50, bg="#eeeeee")
     L2 = Label(TopFrame, text="None", width=10, bg="#eeeeee" )
     Mode.pack(side=LEFT)
     L1.pack(side=LEFT)
     L2.pack(side=LEFT)

     Scroll  = Scrollbar(TextFrame)
     Text    = Text(TextFrame, width=80, yscrollcommand = Scroll.set)
     Scroll.pack( side = RIGHT, fill=Y )
     Text.pack()
     Scroll.config( command = Text.yview )


     ReadButton = Button(master=ModeFrame, text="READ", command=set_read)
     WriteButton = Button(master=ModeFrame, text="WRITE", command=set_write)
     KeyButton = Button(master=ModeFrame, text="KEYS", command=set_key)
     SetupButton = Button(master=ModeFrame, text="SETUP", command=set_setup)
     ReadButton.pack(padx=20, side=LEFT, pady=5)
     WriteButton.pack(padx=20, side=LEFT, pady=5)
     KeyButton.pack(padx=20, side=LEFT, pady=5)
     SetupButton.pack(padx=20, side=LEFT, pady=5)

     # control buttons
     Button1 = Button(master=ControlFrame, text="", width=15, command=action1)
     Button2 = Button(master=ControlFrame, text="", width=15, command=action2)
     Button3 = Button(master=ControlFrame, text="", width=15, command=action3)
     Fill = Label(ControlFrame, text="", width=15)
     Button1.pack(padx=20, side=LEFT)
     Button2.pack(padx=20, side=LEFT)
     Fill.pack(side=LEFT)
     Button3.pack(padx=20, side=RIGHT)



     # right frame
     PoweroffButton = Button(master=RightFrame, text=" POWER OFF ", command=do_poweroff, width=14)
     Fill2 = Label(RightFrame, text="", height=2)
     if os.path.islink("/etc/systemd/system/multi-user.target.wants/cryptoboned.service"):
          if "ALLINONE" in send_command("GETALLINONE"):
	       Fill2.pack(pady=5)
          else:	  
               PoweroffButton.pack(pady=7) 

     FillRight = Label(RightFrame, height=0, width=30)
     FillRight.pack(pady=0)
     
     SelectBox = Frame(RightFrame)
     L = Label(SelectBox, text="", bg="yellow", width=30)
     L.pack()
     BoxFrame = Frame(master=SelectBox)
     XScroll  = Scrollbar(BoxFrame, orient=HORIZONTAL)
     Box = Listbox(BoxFrame, height=17, width=30, xscrollcommand = XScroll.set)
     XScroll.config(command=Box.xview)
     XScroll.pack(side=BOTTOM, fill=X )
     Box.pack()
     BoxFrame.pack()
     SelectButton = Button(master=SelectBox, text="Select", command=select)
     SelectButton.pack(pady=5)

     # left frame
     # Key Management
     Key1 = Frame(LeftFrame, height=100, pady=10)
     Key2 = Frame(LeftFrame, height=100, pady=10)
     Key3 = Frame(LeftFrame, height=100, pady=10)
     KL1 = Label(Key1, text="Register a New Contact", font=Title, bg="yellow", width=25)
     KL2 = Label(Key2, text="Change Email Address", font=Title, bg="yellow", width=25)
     KL3 = Label(Key3, text="Print New Keys",font=Title, bg="yellow", width=25)
     

     # first Key frame 
     SubKL1 = Label(Key1, text="Email Address", font=Bold, bg="white", width=25)
     SubKL2 = Label(Key1, text="Initial Secret", font=Bold, bg="white", width=25)
     KL1Info = Label(Key1, text="      Enter an initial secret for a new contact email address that is not yet registered      ", font=Info, bg="#ffeeee")
     Email   = Entry(Key1, width=40) 
     InitKey = Entry(Key1, width=40) 
     K1Button = Button(master=Key1, text="Register", command=register)
     
     KL1.grid(row=0, column=0, columnspan=2)
     KL1Info.grid(row=1, column=0, columnspan=2, padx=3, pady=5)
     SubKL1.grid(row=2, column=0, padx=3, pady=5)
     Email.grid(row=2, column=1, padx=3, pady=5)
     SubKL2.grid(row=3,column=0, padx=3, pady=5)
     InitKey.grid(row=3, column=1, padx=3, pady=5)
     K1Button.grid(row=4, column=0, columnspan=2, padx=3, pady=5)
     
     # second Key frame 
     OldName = StringVar(Key2)
     OldName.set("Contact Email Address") # initial value

     SubKL3 = OptionMenu(Key2, OldName, "Contact Email Address", "NN1", "NN2", "NN3")
     SubKL4 = Label(Key2, text="New Contact Email Address", font=Bold, bg="white", width=25)
     KL2Info = Label(Key2, text="         Change the email address for NN1,NN2 and NN3 or any registered contact         ", font=Info, bg="#ffeeee")
     OldEmail   = Entry(Key2, width=40)
     NewEmail = Entry(Key2, width=40) 
     K2Button = Button(master=Key2, text="Change", command=change_email)
     
     KL2.grid(row=0, column=0, columnspan=2)
     KL2Info.grid(row=1, column=0, columnspan=2, padx=3, pady=5)
     SubKL3.grid(row=2, column=0, padx=3, pady=5)
     OldEmail.grid(row=2, column=1, padx=3, pady=5)
     SubKL4.grid(row=3,column=0, padx=3, pady=5)
     NewEmail.grid(row=3, column=1, padx=3, pady=5)
     K2Button.grid(row=4, column=0, columnspan=2)

     # third Key frame 
     KL3.grid(row=0, column=0)
     K3Button = Button(master=Key3, text="Generate new secrets", command=print_secrets)
     K3Button.grid(row=1, column=0, pady=5)
    
     # Setup frame
     Setup1 = Frame(LeftFrame, height=100, pady=10)
     SL1 = Label(Setup1, text="Setup the Mail Server for Incoming Email", font=Title, bg="yellow", width=40)
     
     InfoPanel = Label(Setup1, text="" , height=10)
     
     SubSL1 = Label(Setup1, text="Mail Server Name", font=Bold, bg="white", width=24)
     SubSL2 = Label(Setup1, text="User Name", font=Bold, bg="white", width=24)
     SubSL3 = Label(Setup1, text="Password", font=Bold, bg="white", width=24)
     SL1Info = Label(Setup1, text="         In order to receive emails you must use an existing mail server account.           ", font=Info, bg="#ffeeee")
     Hostname = Entry(Setup1, width=40) 
     Username = Entry(Setup1, width=40) 
     Password = Entry(Setup1, width=40, show="*") 
     S1Button = Button(master=Setup1, text="Update Mail Server Setup", command=mailserver_setup)
     ShowButton = Button(master=Setup1, text="Show Setup", command=show_mailserver_setup)
     
     SL1.grid(row=0, column=0, columnspan=2)
     SL1Info.grid(row=1, column=0, columnspan=2, padx=3, pady=5)
     SubSL1.grid(row=2, column=0, padx=3, pady=5)
     Hostname.grid(row=2, column=1, padx=3, pady=5)
     SubSL2.grid(row=3,column=0, padx=3, pady=5)
     Username.grid(row=3, column=1, padx=3, pady=5)
     SubSL3.grid(row=4,column=0, padx=3, pady=5)
     Password.grid(row=4, column=1, padx=3, pady=5)
     ShowButton.grid(row=5, column=0,  padx=3, pady=5)
     S1Button.grid(row=5, column=1,  padx=3, pady=5)
     InfoPanel.grid(row=6, column=0, columnspan=2)
     
     
     QuitButton = Button(master=RightFrame, text="Exit!", command=terminate_GUI, width=14)
     QuitButton.place(x=60, y=432) 
   
     
     # pack frames

     StatusFrame.pack()
     ModeFrame.pack()
     TopFrame.pack()
     TextFrame.pack()
     LeftFrame.pack(side=LEFT)
     RightFrame.pack(padx=8,side=LEFT, fill=Y)
     MainFrame.pack()
     BottomFrame.pack()
     Name = "none"
     
     #Result = send_command("STATUS")
     #if ("failed: local" in Result) or (len(Result) == 0):
     if not os.path.islink("/etc/systemd/system/multi-user.target.wants/cryptoboned.service"):
          print
          print "So you want to activate your Crypto Bone?"
	  print 
	  print "Only the administrator user (root) can do that."
	  print
	  print "To start the activation of your Crypto Bone,"
	  print "please enter the system administrator's password:"
	  print
	  unix("su root -c /usr/lib/cryptobone/sudogetuser")
	  print
	  print "Please REBOOT your computer now to create the missing secrets."
	  print "You should never get back here again as the cryptobone daemon"
	  print "will do its job from now on."
	  print "Please REBOOT your computer now to create the missing secrets."
     
     RESULT = unix("pidof /usr/lib/cryptobone/cryptoboned")
     if "x"+RESULT == "x" :
          # crypto bone daemon is not running
	  import sys
          showerror('Crypto Bone Daemon failed', "You need to reboot your computer because the Crypto Bone Daemon is not running.")
	  sys.exit(2)

     print "Checking status ..."
     check_status() 

     Window.mainloop()

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