#!/usr/bin/python

######################################## Monitoring Client ########################################
#
#   (c) 2010-2017, All rights reserved. Terms posted at www.monitoringclient.com/eula
#
#   Bug and security reports to www.monitoringclient.com/reports
#
###################################################################################################

import os, sys
import plistlib
import time
from subprocess import Popen, PIPE

#############################################################################################
##### Set our temp ClientGroup file, and try to make the MonitoringClient temp directory
#############################################################################################

##### Hopefully the following is true:
# sys.argv[1] = Full path to the package.  Ex: /home/user/Desktop/MonitoringClient.pkg
# sys.argv[2] = Full path to target install destination
# sys.argv[3] = Mount point of destination Volume
# sys.argv[4] = Root folder for the current system

# Old Watchman Path
old_path = os.path.join(sys.argv[2], 'Library', 'Watchman')

# Should pull the Install target destination
install_LOC = os.path.join(sys.argv[2], "Library", "MonitoringClient")

# Path to diskjournald.enabled, so it can restart itself later
diskjournald_enabled_LOC = os.path.join( install_LOC, 'ClientData', 'LocalInfo', 'diskjournald.enabled' )

# Hopefully, sys.argv[1] will pull the package location
cid_LOC = os.path.join(sys.argv[1], 'ClientGroup.txt')

# Target directory for temporary CID from the installerplugin
tmp_LOC = os.path.join(sys.argv[2], "private", "tmp", "MonitoringClientPlugin")

# Target temp CID file
cid_FILE = os.path.join(tmp_LOC, "ClientGroup-proposal.txt")


###################################################################################################
##### GUI for getting/confirming ClientGroup Left as a backup in case the Installer plugin misses
###################################################################################################

class Get_CID:
	def __init__(self, master, ClientGroup):
		frame = Frame()
		frame.grid()

		self.master = master
		master.title("Client Group")
		
			# Now we build all our widgets (objects in the window)

				# The text lines
		line1 = Label(frame, text="Enter a Group name below.")
		line1.grid(row=0, column=0, columnspan=2)
		line2 = Label(frame, text="Good names reference a company, family, or department name.")
		line2.grid(row=1, column=0, columnspan=2)
		line3 = Label(frame, text="Names can be changed later.")
		line3.grid(row=2, column=0, columnspan=2)

				# The entry field
		self.entry = Entry(frame, width=50)
		self.entry.grid(row=3, column=0, columnspan=2, padx=10, pady=10)

				# Inserts the received ClientGroup into the entry field
		self.entry.insert(0, ClientGroup)

				# Bind ENTER key to entry field
		self.entry.bind("<Return>", self.get_ID)

				# The 'Abort' Button
		self.abortButton = Button(frame, text="Abort", command=self.abort)
		self.abortButton.grid(row=4, column=0)

				# The OK/Timer Button
		self.okButton = Button(frame, text="OK", command=self.get_ID)
		self.okButton.grid(row=4, column=1)

				# This sets the focus to the entry field
		self.entry.focus_set()


# This is what happens when when we either click the OK button,
# or the timer runs out.
	def get_ID(self):
		
			# Get the content of the entry field
		newCID = self.entry.get()
		
			# Split it into lines
		newCID_lines = newCID.split("\n")
		
			# If we have more than one line, something's wrong.  Throw an error.
		if (len(newCID_lines) > 1):
			self.error("Too many lines")
			
			# Otherwise, write the contents to the temp file.
		else:
			FILE = open(cid_FILE, 'w')
			FILE.write(newCID)
			FILE.close()
			root.quit()


# This throws up a TopLevel (Pop-up) window when we have an error
	def error(self, err_text):
		toplevel = Toplevel()
		toplevel.title("Error")
		toplevel.config(height=200, width=200)
		msg = Message(toplevel, text=err_text)
		msg.grid(row=0, column=0)
		button = Button(toplevel, text="OK", command=toplevel.destroy)
		button.grid(row=1, column=0)


# When you click the 'Abort' button.  Exits the entire script, with
# an exit status of 2
	def abort(self):
		os.remove(cid_FILE)
		os.rmdir(tmp_LOC)
		sys.exit(2)


###################################################################################################
##### Setting up Paths
###################################################################################################

# IF installation path exists, chmod 755, chown root wheel
if os.path.exists(install_LOC):
	for root, dirs, files in os.walk(install_LOC):
		for d in dirs:
			os.chmod(os.path.join(root, d), int('755', 8))
			os.chown(os.path.join(root, d), 0, 0)
		for f in files:
			os.chmod(os.path.join(root, f), int('755', 8))
			os.chown(os.path.join(root, f), 0, 0)
		
	cs_plist = os.path.join(install_LOC, 'ClientSettings.plist')
	if os.path.exists(cs_plist):
		Popen('/usr/bin/plutil -convert xml1 %s' % cs_plist, shell=True, stdout=PIPE, stderr=PIPE).wait()

# Create temp dir
try: os.mkdir(tmp_LOC)
except: pass


#############################################################################################
##### Look for and remove 'Watchman' branded versions
#############################################################################################

if os.path.isdir(old_path):
	import shutil		# Need shutil to remove non-empty directory trees

	# Unload the scheduler plists:
	Popen('/bin/launchctl unload /Library/LaunchDaemons/com.watchmanmonitoring.client.plist', shell=True).wait()
	Popen('/bin/launchctl unload /Library/LaunchDaemons/com.watchmanmonitoring.updater.plist', shell=True).wait()
	
	# Remove the scheduler plist:
	try: os.remove('/Library/LaunchDaemons/com.watchmanmonitoring.client.plist')
	except (OSError, IOError): pass
	try: os.remove('/Library/LaunchDaemons/com.watchmanmonitoring.updater.plist')
	except (OSError, IOError): pass

	#Remove the installation receipts, 
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.client.plist')
	except (OSError, IOError): pass
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.client.bom')
	except (OSError, IOError): pass
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.update.plist')
	except (OSError, IOError): pass
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.update.bom')
	except (OSError, IOError): pass
	try: shutil.rmtree('/Library/Receipts/Watchman Client.pkg')
	except (OSError, IOError): pass
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.clientupdater.plist')
	except (OSError, IOError): pass
	try: os.remove('/var/db/receipts/com.watchmanmonitoring.clientupdater.bom')
	except (OSError, IOError): pass
	try: shutil.rmtree('/Library/Receipts/WatchmanUpdater.pkg')
	except (OSError, IOError): pass
	
	# Remove the PrefPane and the old Watchman.py
	try: shutil.rmtree('/Library/PreferencePanes/Watchman.prefPane')
	except (OSError, IOError): pass
	
	# Remove Plugins directory
	try: shutil.rmtree(os.path.join(old_path, 'Plugins'))
	except (OSError, IOError): pass
	
	# Remove the old Updater directory
	try: shutil.rmtree(os.path.join(old_path, 'Updater'))
	except (OSError, IOError): pass

	# Remove the old Updater directory
	try: shutil.rmtree(os.path.join(old_path, 'Uninstaller'))
	except (OSError, IOError): pass

	# Move /Watchman to /MonitoringClient
	try: shutil.move(old_path, install_LOC)
	except (OSError, IOError): pass

	# Change the plist name
	shutil.move(os.path.join(install_LOC, 'Watchman.plist'), os.path.join(install_LOC, 'ClientSettings.plist'))
	
		# Change the plist name
	try: shutil.move(os.path.join(install_LOC, 'PluginSupport', 'Volumes.plist'), os.path.join(install_LOC, 'PluginSupport', 'check_volumes_settings.plist'))
	except (OSError, IOError): pass


	# Remove the old Client Starter
	os.remove(os.path.join(install_LOC, 'Watchman.py'))


#############################################################################################
##### Now we do the checks and the work
#############################################################################################

# If the diskjournald.enabled file exists - remove it and let dnt/launchd handle restarting later
if os.path.exists( diskjournald_enabled_LOC ): os.remove( diskjournald_enabled_LOC )

# If our Installer Plugin created the tmp file for us, we don't have
#	anything to do
if os.path.isfile(cid_FILE): sys.exit(0)

# Check to see if the ClientGroup is set in the postflight
postinst = os.path.join( sys.argv[1], 'Contents', 'Resources', 'postflight' )
if os.path.exists( postinst ):
	FILE = open( postinst, 'rU' )
	data = FILE.read()
	FILE.close()

	for line in data.split('\n'):
		if ( 'ClientGroup = ' in line ) and ( line != 'ClientGroup = \'\'' ): sys.exit(0)

# If a ClientGroup.txt file is provided, try to copy that to the temp file
# If the copy fails, or the source doesn't exist, write a blank cid
def write_blank_cid():
	FILE = open(cid_FILE, 'w')
	FILE.write("\n")
	FILE.close()

# The package contents don't like being referenced via cp command
# So we have to manually read and write the ClientGroup contents to tmp
if os.path.isfile(cid_LOC):
	try:
		FILE = open(cid_LOC, 'rU')
		data = FILE.read()
		FILE.close()
		
		FILE = open(cid_FILE, 'w')
		FILE.write(data)
		FILE.close()
	except: write_blank_cid()
else: write_blank_cid()

# If this isn't a fresh install, check the old ClientGroup
if os.path.exists( os.path.join( install_LOC, 'ClientSettings.plist' ) ):
	ClientGroup = plistlib.readPlist( os.path.join( install_LOC, 'ClientSettings.plist' ) )['ClientGroup']

# Otherwise, read from our proposal
else:
	FILE = open(cid_FILE, 'r')
	lines = FILE.readlines()
	FILE.close()
	ClientGroup = lines[0].strip()

# check our environment ...
if not ('COMMAND_LINE_INSTALL' in os.environ) and ClientGroup == "":

	# If we STILL don't have a ClientGroup-Proposal, Tkinter is going to rear its ugly head
	try:
		from Tkinter import *
		root = Tk()
		root.resizable(0, 0)
		app = Get_CID(root, ClientGroup)
		root.mainloop()
	except: pass
