<!--- Params needed to run an update (Hotfix, Patch, or Upgrade)  --->
<cfparam name="form.Type" default="#IIf(IsDefined('url.Type'), 'url.Type', DE(''))#">
<cfparam name="form.UpdateVersion" default="#IIf(IsDefined('url.UpdateVersion'), 'url.UpdateVersion', DE(''))#">
<cfparam name="form.UpdateFile" default="#IIf(IsDefined('url.UpdateFile'), 'url.UpdateFile', DE(''))#">
<cfparam name="form.MinCF" default="#IIf(IsDefined('url.MinCF'), 'url.MinCF', DE(''))#">
<cfparam name="form.MinRailo" default="#IIf(IsDefined('url.MinRailo'), 'url.MinRailo', DE(''))#">
<cfparam name="form.MinSQL" default="#IIf(IsDefined('url.MinSQL'), 'url.MinSQL', DE(''))#">
<cfparam name="form.AdminPassword" default="#IIf(IsDefined('url.AdminPassword'), 'url.AdminPassword', DE(''))#">
<cfparam name="form.ServerPassword" default="#IIf(IsDefined('url.ServerPassword'), 'url.ServerPassword', DE(''))#">
<cfparam name="form.HotfixID" default="">
<cfparam name="form.Description" default="">

<!--- determine path variables for "Intranet" folder name, path to it, root install path, etc --->
<cfset intranetRoot = application.paths.sDrive>
<cfset installRoot = Left(intranetRoot, intranetRoot.lastIndexOf('\'))>
<cfset urlFirstFolder = ListFirst(cgi.script_name, "/")>
<cfset intranetFolder = ListLast(intranetRoot, "\")>

<!--- Unpackage any prerequisite files (if we have any and they haven't already been unpackaged) --->
<cfif NOT IsDefined("cookie.serverPasswordPrereq") AND FileExists("#intranetRoot#\Updates\scripts\prereq.zip")>
	<cfzip action="unzip" 
		file="#intranetRoot#\Updates\scripts\prereq.zip"
		destination="#intranetRoot#" 
		overwrite="yes" />
		
	<cfset cookieService = CreateObject("component", "Intranet.sqbox.service.common.CookieService")>
	<cfset oCookie = StructNew()>
	<cfset oCookie.httponly = true>
	<cfset oCookie.secure = IIf(FindNoCase("https:", session.sWebRoot), true, false)>
	<cfset oCookie.expires = DateAdd("n", 5, Now())>
	<cfset oCookie.name = "serverPasswordPrereq">
	<cfset oCookie.value = true>
	<cfset cookieService.setCookie(argumentcollection = oCookie)>
	
	<!--- relaunch update and blowthrough to progress --->
	<cfoutput>{"sReturnMsg":"/Admin/SiteSettings/install_update_popup.cfm?fwreinit=1&Type=#form.Type#&UpdateVersion=#form.UpdateVersion#&UpdateFile=#form.UpdateFile#&MinCF=#form.MinCF#&MinSQL=#form.MinSQL#&blowthrough=true&AdminPassword=#form.AdminPassword#&ServerPassword=#form.ServerPassword#"}</cfoutput>
	<cfabort>
</cfif>

<!--- Include functions file (UDFs used by patch/upgrade) --->
<cfinclude template="udfs.cfm">

<!--- if this is a hotfix, we have to get the ID & description from the update.xml file --->
<cfif form.Type EQ "Hotfix">
	<cfzip action="read" 
		file="#intranetRoot#\Updates\#form.UpdateFile#" 
		entrypath="update.xml" 
		variable="sUpdateInfo">
	<cfset xmlUpdate = XmlParse(sUpdateInfo)>
	<cfset form.HotfixID = ReplaceNoCase(xmlUpdate.item.title.XmlText, "Hotfix ", "")>
	<cfset form.Description = xmlUpdate.item.description.XmlText>	
	<cfset form.ReleaseDate = DateConvert("utc2Local", utcStringToDateTime(xmlUpdate.item.pubDate.XmlText))>
</cfif>

<!--- Import the current tag library for the progress bar --->
<cfimport taglib="../../cfcustomtags/devtools" prefix="devtools">

<!--- Ensure we have a long timeout --->
<cfsetting requesttimeout="60000">

<!--- Where to log update to --->
<cfset sLogFileName = "#sApplicationName#_#form.Type#_#form.UpdateVersion#">

<!--- Check CF/Railo & SQL Versions are valid --->
<cfif FindNoCase("ColdFusion", server.ColdFusion.ProductName) AND ListFirst(server.ColdFusion.ProductVersion) LT form.MinCF>
	<cfoutput>{"sReturnMsg":"errorIntranet Connections Version #form.UpdateVersion# is only compatible with a ColdFusion version of #form.MinCF# or greater.  Your current version is #application.config.CFVersion#. Please contact Intranet Connections support for instructions on how to upgrade your ColdFusion installation"}</cfoutput>
	<cfabort>
<cfelseif FindNoCase("Railo", server.ColdFusion.ProductName)
	AND (ListFirst(server.Railo.Version, ".") LT ListFirst(form.MinRailo, ".")
		OR (ListFirst(server.Railo.Version, ".") EQ ListFirst(form.MinRailo, ".")
			AND ListGetAt(server.Railo.Version, 2,  ".") LT ListGetAt(form.MinRailo, 2, ".")))>
	<cfoutput>{"sReturnMsg":"errorIntranet Connections Version #form.UpdateVersion# is only compatible with a Railo version of #form.MinRailo# or greater.  Your current version is #application.config.CFVersion#. Please contact Intranet Connections support for instructions on how to upgrade your Railo installation"}</cfoutput>
	<cfabort>		
</cfif>
<cfquery name="qrySQLInfo" datasource="#application.config.DSN#">
	SELECT CONVERT(VARCHAR(100), SERVERPROPERTY('productversion')) AS ProductVersion, 
		CONVERT(VARCHAR(100), SERVERPROPERTY ('productlevel')) AS ProductLevel, 
		CONVERT(VARCHAR(100), SERVERPROPERTY ('edition')) AS Edition
</cfquery>
<cfif ListFirst(qrySQLInfo.ProductVersion, '.') LT form.MinSQL>
	<cfoutput>{"sReturnMsg":"errorIntranet Connections Version #form.UpdateVersion# is only compatible with a SQL Server version of #form.MinSQL# or greater.  Your current version is #application.config.SQLVersion#. Please contact Intranet Connections support for instructions on how to upgrade your SQL Server installation"}</cfoutput>
	<cfabort>
</cfif>

<!--- Validate Railo admin password --->
<cfset sAction = "password">
<cfinclude template="railo.cfm">

<cfif form.Type NEQ "Hotfix">
	<!--- Validate Railo server admin password --->
	<cfset sAction = "serverPassword">
	<cfinclude template="railo.cfm">
</cfif>


<!--- Indicate update is starting --->
<cfset sLogMessage = "Starting the #LCase(form.Type)# process">
<devtools:progress_bar_increment sMessage="#sLogMessage#">
<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
<cfthread action="sleep" duration="500" />

<cftransaction action="begin">
	<cftry>
		<!--- STEP 1: Database Schema Changes, File Migration, File Cleanup (Not applicable for hotfixes) --->
		<cfif form.Type NEQ "Hotfix">
			<cfset sLogMessage = "Updating the database schema, data, and performing migrations">
			<devtools:progress_bar_increment sMessage="#sLogMessage#">
			<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
			
			<cfset sLogMessage = "Updating Railo Performance/Caching inspect templates to 'always'.">
			<devtools:progress_bar_increment sMessage="#sLogMessage#">
			<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
			<!--- read the client settings first --->
			<cfadmin action="getPerformanceSettings" type="web" password="#form.AdminPassword#" returnvariable="WebPerformanceSettings">
			<cfadmin action="updatePerformanceSettings" type="web" password="#form.AdminPassword#" typeChecking="true" inspectTemplate="always" />
			<!--- set white space suppression --->
			<cfadmin action="updateOutputSetting" type="web" password="#form.AdminPassword#" cfmlWriter="white-space-pref" suppressContent="false" allowCompression="false" contentLength="" bufferOutput="true">

			<cfthread action="sleep" duration="500" />
		
			<!--- run patches for current major version --->
			<cfset sVersion = application.config.appSettingsRepository.readSetting("Version")>
			<cfset sCurrentMajor = ListDeleteAt(sVersion, ListLen(sVersion, "."), ".")>
			<cfset nCurrentPatch = ListLast(sVersion, ".")>
			<cfinclude template="patch.cfm">
		
			<!--- run upgrade --->
			<cfif form.Type EQ "Upgrade">
				<!---<cfinclude template="upgrade.cfm">---> <!--- NOTE: uncomment this if you want to make a complex package. --->
				<cfset form.UpdateVersion = "16.5.0">
				<!--- run applicable patches for next major version --->
				<cfset sCurrentMajor = ListDeleteAt(form.UpdateVersion, ListLen(form.UpdateVersion, "."), ".")>
				<cfset nCurrentPatch = ListLast(form.UpdateVersion, ".")>
				<cfinclude template="patch.cfm">
			</cfif>
		</cfif>
						
		<!--- STEP 2: Update site files from ZIP package --->
		<cfset sLogMessage = "Unpackaging updated files to the intranet">
		<devtools:progress_bar_increment sMessage="#sLogMessage#">
		<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
		<cfthread action="sleep" duration="500" />
		
		<!--- get zip package from update package --->
		<cfzip action="unzip" 
			file="#intranetRoot#\Updates\#form.UpdateFile#" 
			destination="#intranetRoot#\Updates" 
			overwrite="yes" />
			
		<cfif form.Type EQ "Hotfix">
			
			<!--- get a list of files that will be updated --->
			<cfzip action="list" 
				file="#intranetRoot#\Updates\package.zip"
				name="qryHotfix"
				recurse="yes" />
			
			<!--- create hotfix backup location (if not already there) --->
			<cfif NOT DirectoryExists("#intranetRoot#\Updates\Hotfixes")>
				<cfdirectory action="create" directory="#intranetRoot#\Updates\Hotfixes">
			</cfif>
			<cfif NOT DirectoryExists("#intranetRoot#\Updates\Hotfixes\#form.HotfixID#")>
				<cfdirectory action="create" directory="#intranetRoot#\Updates\Hotfixes\#form.HotfixID#">
			</cfif>
			
			<!--- extract hotfix files to backup location --->
			<cfzip action="unzip" 
				file="#intranetRoot#\Updates\package.zip"
				destination="#application.paths.sDrive#\Updates\Hotfixes\#form.HotfixID#\" 
				overwrite="yes" />
			
			<!--- log hot fix info --->
			<cfquery datasource="#application.config.DSN#">
				INSERT INTO	Hotfix (HotfixID, Version, DateBuilt, DateApplied, Description)
				VALUES (
					<cfqueryparam value="#form.HotfixID#" cfsqltype="cf_sql_integer">,
					<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.UpdateVersion#">,
					#CreateODBCDateTime(form.ReleaseDate)#,
					GETDATE(),
					<cfqueryparam cfsqltype="cf_sql_longvarchar" value="#form.Description#">
				)
			</cfquery>
			
			<!--- log every file of hot fix and backup --->
			<cfloop query="qryHotfix">
				<cfset sFilePath = Replace(qryHotfix.name, "/", "\", "all")>
				<cfif qryHotfix.type EQ "file">
					<cfquery datasource="#application.config.DSN#">
						INSERT INTO	HotfixFile (HotfixID, FilePath)
						VALUES (
							<cfqueryparam value="#form.HotfixID#" cfsqltype="cf_sql_integer">,
							<cfqueryparam cfsqltype="cf_sql_varchar" value="#sFilePath#">
						)
					</cfquery>
					<cfset sLivePath = sFilePath>
					<cfif ListFirst(sFilePath, "\") EQ "Intranet">
						<cfset sLivePath = Replace(sFilePath, "Intranet", intranetFolder, "one")>
					</cfif>
					<cfif FileExists("#installRoot#\#sLivePath#")>
						<cffile action="copy" 
							destination="#intranetRoot#\Updates\Hotfixes\#form.HotfixID#\#sFilePath#" 
							source="#installRoot#\#sLivePath#">
					<cfelse>
						<cffile action="delete" 
							file="#intranetRoot#\Updates\Hotfixes\#form.HotfixID#\#sFilePath#">
					</cfif>
				</cfif>
			</cfloop>
			
			<!--- unzip updated files from package zip onto site (all will be open source and deleted by next patch/upgrade) --->
			<cfset deployPackage(packagePath = "#intranetRoot#\Updates\package.zip", 
				intranetRoot = intranetRoot, installRoot = installRoot, intranetFolder = intranetFolder)>
				
		<cfelse>
				
			<!--- temporarily remove secure archive mapping (so we can overwrite .ras file) --->
			<cfset sAction = "removeMapping">
			<cfinclude template="railo.cfm">
			
			<!--- delete all cfm, cfml, cfr, cfc files (that are not open source and are part of the manifest) --->
			<cfinclude template="opensource.cfm" />
			<cfzip action="list" file="#intranetRoot#\IntranetConnections.ras" name="qryManifest" recurse="yes" />
			<cfset deleteCFML(folder = intranetRoot, lstOpenSource = lstOpenSource, qryManifest = qryManifest)>
			
			<!--- unzip updated files from package zip onto site --->
			<cfset deployPackage(packagePath = "#intranetRoot#\Updates\package.zip", 
				intranetRoot = intranetRoot, installRoot = installRoot, intranetFolder = intranetFolder)>
				
			<!--- recreate secure archive mapping --->
			<cfset sAction = "updateMapping">
			<cfinclude template="railo.cfm">

			<cfset sLogMessage = "Updating Railo Performance/Caching inspect templates back to original setting.">
			<devtools:progress_bar_increment sMessage="#sLogMessage#">
			<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
			<cfadmin action="updatePerformanceSettings" type="web" password="#form.AdminPassword#" typeChecking="#WebPerformanceSettings.typeChecking#" inspectTemplate="#WebPerformanceSettings.InspectTemplate#" />
			

		</cfif>
				
		<!--- STEP 3: Update version number in database and wipe hotfixes (patch or upgrade) --->
		<cfif form.Type NEQ "Hotfix">
			<cfset sLogMessage = "Updating the version number in the database">
			<devtools:progress_bar_increment sMessage="#sLogMessage#">
			<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
			<cfthread action="sleep" duration="500" />
			
			<cfquery datasource="#application.config.DSN#">
				DELETE FROM HotfixFile
				DELETE FROM Hotfix
			</cfquery>
			<cfquery datasource="#application.config.DSN#">
				UPDATE	AppSetting
				SET		Value = <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.UpdateVersion#">
				WHERE	Name = 'Version'
			</cfquery>
			<cfquery datasource="#application.config.DSN#">
				UPDATE	AppSetting
				SET		Value = '#DateFormat(Now(), "yyyy-mm-dd")# #TimeFormat(Now(), "HH:mm:ss")#'
				WHERE	Name = 'PatchDate'
			</cfquery>
			
			<!--- update log level to default of errors only --->
			<cfset application.config.appSettingsRepository.updateSetting("LOGLEVEL", 1)>
		</cfif>
		
		<!--- STEP 4: Commit database transaction --->
		<cfset sLogMessage = "Committing database changes">
		<devtools:progress_bar_increment sMessage="#sLogMessage#">
		<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
		<cfthread action="sleep" duration="500" />
		
		<cftransaction action="commit" />
			
		<!--- STEP 5: Delete update files --->
		<cfset sLogMessage = "Deleting temporary #LCase(form.Type)# files">
		<devtools:progress_bar_increment sMessage="#sLogMessage#">
		<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
		<cfthread action="sleep" duration="1000" />
		<cftry>		
			<cfif DirectoryExists("#intranetRoot#\Updates\package\")>
				<cfdirectory action="delete" directory="#intranetRoot#\Updates\scripts\" recurse="true"> 
			</cfif>
			<cfif DirectoryExists("#intranetRoot#\Updates\scripts\")>
				<cfdirectory action="delete" directory="#intranetRoot#\Updates\scripts\" recurse="true"> 
			</cfif>
			<cfif FileExists("#intranetRoot#\Updates\#form.UpdateFile#")>
				<cffile action="delete" file="#intranetRoot#\Updates\#form.UpdateFile#">
			</cfif>
			<cfif FileExists("#intranetRoot#\Updates\package.zip")>
				<cffile action="delete" file="#intranetRoot#\Updates\package.zip">
			</cfif>
			<cfif FileExists("#intranetRoot#\Updates\update.xml")>
				<cffile action="delete" file="#intranetRoot#\Updates\update.xml">
			</cfif>
			<cfif form.Type NEQ "Hotfix" AND DirectoryExists("#intranetRoot#\Updates\Hotfixes")>
				<cfdirectory action="delete" directory="#intranetRoot#\Updates\Hotfixes" recurse="yes">
			</cfif>
			<cfcatch type="any">
				<cflog file="#sLogFileName#" type="error" text="#cfcatch.message#">
			</cfcatch>
		</cftry>
		
		<cfset sLogMessage = "Clearing template and component cache.">
		<devtools:progress_bar_increment sMessage="#sLogMessage#">
		<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
		
		<!--- SUCCESS --->
		<cfset sLogMessage = "#form.Type# successfully installed. Your intranet application will now be restarted.">
		<devtools:progress_bar_increment sMessage="#sLogMessage#">
		<cflog file="#sLogFileName#" type="information" text="#sLogMessage#">
		
		<cfthread action="sleep" duration="500" />
		
		<cfif form.Type NEQ "Hotfix">
		<cfadmin
		    action="restart"
		    type="server"
		    password="#form.ServerPassword#">
		</cfif>
		
		<cfoutput>{"sReturnMsg":"topAdmin/SiteSettings/site_settings.cfm?tabidx=1&fwreinit=1&run_task=true"}</cfoutput>
		
		<cfcatch type="any">
			<!--- rollback any commited DB changes --->
			<cftransaction action="rollback" />			
				
			<!--- write error to the log file --->
			<cfset sErrorMessage = "Error applying #LCase(form.Type)#">
			<cfif IsDefined("cfcatch.message")>
				<cfset sErrorMessage &= ", Error: #cfcatch.message#">    
            </cfif>
            <cfif IsDefined("cfcatch.detail")>
				<cfset sErrorMessage &= ", Detail: #cfcatch.detail#">    
            </cfif>
            <cfif IsDefined("cfcatch.tagContext") AND ArrayLen(cfcatch.tagContext)>
				<cfset maxTagCount = 10>
				<cfset tagCount = 0>
				<cfloop from="1" to="#ArrayLen(cfcatch.tagContext)#" index="nIdx">
					<cfset tagCount++>
					<cfset sErrorMessage &= ", Template: #cfcatch.tagContext[nIdx].line# in #cfcatch.tagContext[nIdx].template#">
					<cfif tagCount EQ maxTagCount>
						<cfbreak>
					</cfif>
				</cfloop>
            </cfif>
            <cfif IsDefined("cfcatch.Sql")>
                <cfset sErrorMessage &= ", SQL: #cfcatch.Sql#">
            </cfif>
			<cflog file="#sLogFileName#" type="error" text="#sErrorMessage#">
			
			<!--- report error to user --->
			<devtools:progress_bar_abort sMessage="An error has occurred in the #LCase(form.Type)# script. Please check the log #sLogFileName#.log">
			<cfset sErrorMessage = 'error' & sErrorMessage>
			<cfif IsDefined("request.functions.removeJSONPrefix")>
				<cfset sErrorMessage = request.functions.removeJSONPrefix(SerializeJSON(sErrorMessage))>
			<cfelse>
				<cfset sErrorMessage = SerializeJSON(sErrorMessage)>
			</cfif>
			<cfoutput>{"sReturnMsg":#sErrorMessage#}</cfoutput>
			<cfabort>
			
			<!--- cleanup temporary update files --->
			<cfif DirectoryExists("#intranetRoot#\Updates\package\")>
				<cfdirectory action="delete" directory="#intranetRoot#\Updates\scripts\" recurse="true"> 
			</cfif>
			<cfif DirectoryExists("#intranetRoot#\Updates\scripts\")>
				<cfdirectory action="delete" directory="#intranetRoot#\Updates\scripts\" recurse="true"> 
			</cfif>
			<cfif FileExists("#intranetRoot#\Updates\package.zip")>
				<cffile action="delete" file="#intranetRoot#\Updates\package.zip">
			</cfif>
			<cfif FileExists("#intranetRoot#\Updates\update.xml")>
				<cffile action="delete" file="#intranetRoot#\Updates\update.xml">
			</cfif>
		</cfcatch>
	</cftry>
</cftransaction>
