First commit. It's working!
authorDan
Wed, 27 May 2009 01:05:23 -0400
changeset 0 67e1cc6cd929
child 1 ac5bcb4e5284
First commit. It's working!
enano-bundle.nsi
gfx/application.html
gfx/enano-bg.bmp
gfx/enanocms-module.png
inst-resources/apacheconfig.nsh
inst-resources/applist.nsh
inst-resources/bitnamiutils.nsh
inst-resources/core-files.nsh
inst-resources/dbal.nsh
inst-resources/kickstart.nsh
inst-resources/mysql.nsh
inst-resources/mysqlutil.php
inst-resources/postgresql.nsh
inst-resources/postgresqlutil.php
inst-resources/randompass.php
inst-resources/str_replace.nsh
licenses/GPL.txt
pages/DatabaseConfig.ini
pages/DatabaseConfig.nsi
pages/Login.ini
pages/Login.nsi
pages/SiteConfig.ini
pages/SiteConfig.nsi
pages/StackSelect.ini
pages/StackSelect.nsi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/enano-bundle.nsi	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,276 @@
+; Script generated by the HM NIS Edit Script Wizard.
+
+; HM NIS Edit Wizard helper defines
+!define PRODUCT_NAME "Enano CMS"
+!define PRODUCT_VERSION "1.1.6"
+!define PRODUCT_PUBLISHER "Enano CMS Project"
+!define PRODUCT_WEB_SITE "http://enanocms.org"
+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
+!define PRODUCT_SHORTNAME "enanocms"
+
+!ifndef ENANO_ROOT
+!define ENANO_ROOT "Q:\enano-1.1\repo"
+!endif
+
+SetCompressor /FINAL /SOLID lzma
+CRCCheck force
+
+Var wampstack_installed
+Var wappstack_installed
+Var stack_type
+Var stack_instdir
+Var stack_portbit
+Var db_dbmsname
+Var db_rootuser
+Var db_rootpass
+Var db_needroot
+Var db_driver
+Var db_port
+Var db_user
+Var db_password
+Var db_name
+Var enano_user
+Var enano_password
+Var admin_email
+Var site_name
+Var site_desc
+Var site_copyright
+Var url_scheme
+Var start_with
+
+!include "inst-resources\bitnamiutils.nsh"
+!include "inst-resources\dbal.nsh"
+!include "inst-resources\mysql.nsh"
+!include "inst-resources\postgresql.nsh"
+!include "inst-resources\str_replace.nsh"
+!include "inst-resources\kickstart.nsh"
+!include "inst-resources\apacheconfig.nsh"
+!include "inst-resources\applist.nsh"
+
+Function .onInit
+  Call BNSetWAMPInstalledFlag
+  Call BNSetWAPPInstalledFlag
+  
+  ; If neither WAMP nor WAPP is installed, die
+  StrCmp $wampstack_installed 0 "" FoundStack
+  StrCmp $wampstack_installed 0 "" FoundStack
+
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Setup could not find any BitNami stacks on your server.$\r$\n\
+                                         $\r$\n\
+                                         Please install a BitNami stack and re-run setup. You can download a BitNami stack for free from http://www.bitnami.org."
+    Abort
+
+  FoundStack:
+FunctionEnd
+
+; ExperienceUI GUI parameters
+!define XPUI_BGIMAGE
+!define XPUI_BGIMAGE_BMP "gfx\enano-bg.bmp"
+!define XPUI_TEXT_COLOR "F2F2F2"
+!define XPUI_TEXT_BGCOLOR "202020" ; irrelevant but still
+!define XPUI_TEXT_LIGHTCOLOR "B4C3EA"
+!define XPUI_ABORTWARNING
+!define XPUI_BRANDINGTEXT "NSIS Installer ${NSIS_VERSION}"
+!define XPUI_BRANDINGTEXT_COLOR_FG "b6d9ff"
+!define XPUI_BRANDINGTEXT_COLOR_BG "4c5b6b"
+!define XPUI_FASTERSKINNING
+
+; MUI 1.67 compatible / XPUI 1.11 (2.0pre) compatible ------
+!ifndef XPUI_SYSDIR
+  !define XPUI_SYSDIR "C:\ExperienceUI\Contrib\ExperienceUI"
+!endif
+!include "${XPUI_SYSDIR}\..\..\Include\XPUI.nsh"
+
+; MUI Settings
+!define MUI_ABORTWARNING
+!define MUI_ICON "inst-resources\generic-install.ico"
+!define MUI_UNICON "inst-resources\generic-uninstall.ico"
+!include "WinMessages.nsh"
+
+; Welcome page
+!insertmacro XPUI_PAGE_WELCOME2
+; License page
+!insertmacro MUI_PAGE_LICENSE "licenses\GPL.txt"
+; Stack selection - automatic unless both stacks are installed
+!include "pages\StackSelect.nsi"
+; Database credentials entry
+!include "pages\DatabaseConfig.nsi"
+; Site config page
+!include "pages\SiteConfig.nsi"
+; User credentials page
+!include "pages\Login.nsi"
+; Components page
+!insertmacro MUI_PAGE_COMPONENTS
+; Instfiles page
+!insertmacro MUI_PAGE_INSTFILES
+; Finish page
+!define XPUI_FINISHPAGE_RUN
+!define XPUI_FINISHPAGE_CHECKBOX_RUN "Go to my new $(^Name) website now"
+!define XPUI_FINISHPAGE_RUN_FUNCTION OpenBitnamiWebsite
+Function OpenBitnamiWebsite
+  ExecShell open "http://localhost$stack_portbit/${PRODUCT_SHORTNAME}/"
+FunctionEnd
+!insertmacro MUI_PAGE_FINISH
+
+!insertmacro XPUI_PAGE_ABORT
+
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_INSTFILES
+
+; Language files
+!insertmacro MUI_LANGUAGE "English"
+
+; Reserve files
+!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
+
+; MUI end ------
+
+; File lists
+!include "inst-resources\core-files.nsh"
+; End file lists
+
+Name "${PRODUCT_NAME}"
+Caption "${PRODUCT_NAME} ${PRODUCT_VERSION} Bitnami installer"
+OutFile "enano-1.1.6-bitnami-setup.exe"
+InstallDir "$PROGRAMFILES\Enano CMS"
+ShowInstDetails show
+ShowUnInstDetails show
+
+Section "-pre"
+  StrCpy $INSTDIR "$stack_instdir"
+  IfFileExists "$INSTDIR\apps\${PRODUCT_SHORTNAME}\htdocs\config.php" 0 +2
+    Delete "$INSTDIR\apps\${PRODUCT_SHORTNAME}\htdocs\config.php"
+SectionEnd
+
+Section "-DatabaseSetup"
+  StrCmp $db_needroot 1 +2
+    Return
+    
+  ; Create database
+  ${db_create} $R0 "$db_rootuser" "$db_rootpass" "$db_name" "$db_user" "$db_password"
+  IntCmp $R0 0 DatabaseCreateSuccess
+    !insertmacro XPUI_HEADER_TEXT "Installation failed" "Could not create the database."
+    DetailPrint "Database creation failed."
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Setup failed to create the database for $(^Name).$\r$\n\
+                                         $\r$\n\
+                                         It's possible that your authentication details were rejected or that there \
+                                         is a bug in the installer. Try removing any special characters (especially \
+                                         quote symbols and backslashes) from your password. Make sure to use only \
+                                         letters, numbers, and underscores in the database name and username."
+    Abort
+  DatabaseCreateSuccess:
+SectionEnd
+
+Section "Enano Core" SEC01
+  SectionIn RO
+  !insertmacro Core_Install
+SectionEnd
+
+Section "Enable GMP in PHP" SecGMP
+  ClearErrors
+  WriteINIStr "$stack_instdir\php\php.ini" "GMP" "extension" "php_gmp.dll"
+  IfErrors 0 +2
+    MessageBox MB_OK|MB_ICONEXCLAMATION "GMP was not automatically enabled in PHP. Logins will be several seconds slower."
+SectionEnd
+
+Section "YubiKey auth plugin" SEC02
+SectionEnd
+
+Section "AjIM2" SEC03
+SectionEnd
+
+Section "Admin Alerts" SEC04
+SectionEnd
+
+Section "RSS Feeds" SEC06
+SectionEnd
+
+Section "News Portal" SEC08
+SectionEnd
+
+Section "Code syntax highlighting" SEC11
+SectionEnd
+
+Section "Wiki functionality extensions" SEC12
+SectionEnd
+
+Section -ConfigureApache
+  DetailPrint "Configuring Apache web server"
+  Call write_apache_config
+  DetailPrint "Restarting Apache"
+  nsExec::Exec '"$SYSDIR\net.exe" stop "$stack_typestackApache"'
+  nsExec::Exec '"$SYSDIR\net.exe" start "$stack_typestackApache"'
+SectionEnd
+
+Section -WriteKickStart
+  Call enano_write_kickstart_script
+SectionEnd
+
+Section -DoEnanoDBSetup
+  Call enano_run_kickstart_script
+SectionEnd
+
+Section -InsertApplistEntry
+  Call enano_add_to_applist
+SectionEnd
+
+Section -AdditionalIcons
+  WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
+  CreateDirectory "$SMPROGRAMS\Enano CMS"
+  CreateShortCut "$SMPROGRAMS\Enano CMS\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
+  CreateShortCut "$SMPROGRAMS\Enano CMS\Uninstall.lnk" "$INSTDIR\apps\${PRODUCT_SHORTNAME}\uninst.exe"
+SectionEnd
+
+Section -Post
+  WriteUninstaller "$INSTDIR\uninst.exe"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
+  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+SectionEnd
+
+; Section descriptions
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "Core components of Enano CMS, necessary to run Enano"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} "Adds support for Yubikey authentication"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} "An AJAX chatbox sidebar gadget for Enano"
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC04} "Provides a sidebar block that alerts you about unapproved comments, inactive users, and pages with requested deletion."
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC06} "Provides the ability to generate RSS feeds based on the latest page edits and comments. It also has a plugin API so plugins can add their own feeds."
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC08} "Provides a portal with news and static content combined onto one page."
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC11} "Parser extension that adds syntax highlighting support using the GeSHi highlighting engine."
+  !insertmacro MUI_DESCRIPTION_TEXT ${SEC12} "Adds several parser extensions that provide MediaWiki-like behavior, including references (footnotes) and Table of Contents support."
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecGMP} "Enables PHP's GMP extension, which speeds up cryptographic operations."
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+
+Function un.onUninstSuccess
+  HideWindow
+  MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
+FunctionEnd
+
+Function un.onInit
+  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
+  Abort
+FunctionEnd
+
+Section Uninstall
+  Delete "$INSTDIR\apps\${PRODUCT_SHORTNAME}\${PRODUCT_NAME}.url"
+
+  !insertmacro Core_Uninstall
+
+  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+  SetAutoClose true
+SectionEnd
+
+; Version Information
+
+VIProductVersion "1.1.6.0"
+VIAddVersionKey /LANG=1033 "ProductName" "Enano CMS"
+VIAddVersionKey /LANG=1033 "Setup Information" "Enano CMS installer module for Windows Apache stacks"
+VIAddVersionKey /LANG=1033 "Comments" "This installer contains a beta build of Enano CMS, use with caution!"
+VIAddVersionKey /LANG=1033 "Publisher Name" "Neal Gompa (King InuYasha), Enano CMS Project"
+VIAddVersionKey /LANG=1033 "LegalCopyright" "©2009 Enano CMS Project"
+VIAddVersionKey /LANG=1033 "FileDescription" "Enano - The CMS that focuses on what matters most: content."
+VIAddVersionKey /LANG=1033 "FileVersion" "${PRODUCT_VERSION}"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gfx/application.html	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,29 @@
+<!-- START BitNami Enano CMS Module enanocms -->
+        <div align="center" class="module_table">
+         <table cellpadding="0" cellspacing="0" >
+          <tr><td class="module_top"><img src="img/module_table_top.png" alt=""></td></tr>
+          <tr>
+          <td class="module_content" valign="top"> 
+            <table cellpadding="0" cellspacing="0">
+              <tr>
+                <td valign="top">
+                <img src="img/enanocms-module.png" alt="">
+                </td>
+                <td valign="top">
+                <h2>BitNami Enano CMS Module</h2>
+                <p>Enano CMS is the open source website management suite and wiki that does everything in beautiful, smooth AJAX action.</p>
+                <div align="right" class="module_access"><a href="/enanocms">Access</a></div>
+                </td>
+              </tr>
+            </table>
+          </td>
+          </tr>
+          <tr>
+          <td class="module_bottom"> 
+          <img src="img/module_table_bottom.png" alt="">
+          </td>
+          </tr>
+          </table>
+        </div>
+        <!-- END BitNami Enano CMS Module enanocms -->
+        
Binary file gfx/enano-bg.bmp has changed
Binary file gfx/enanocms-module.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/apacheconfig.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,74 @@
+/**
+ * Search the Apache configuration for the Include line for this package's Apache settings.
+ * @return int 0 if successful (found line); 1 if not found
+ */
+
+Function search_apache_config
+  FileOpen $0 "$INSTDIR\apache2\conf\httpd.conf" "r"
+  loop:
+    ClearErrors
+    FileRead $0 $1 1024
+    IfErrors done
+    Push $1
+    Push "Include "
+    Call StrStr
+    Pop $2
+    StrCmp $2 "" loop
+      ; This is an include line
+      Push $1
+      Push "/apps/${PRODUCT_SHORTNAME}/"
+      Call StrStr
+      Pop $2
+      StrCmp $2 "" loop
+        ; We found it
+        Push 0
+        FileClose $0
+        Return
+  done:
+  FileClose $0
+  Push 1
+FunctionEnd
+
+Function write_apache_config
+  Call search_apache_config
+  Pop $0
+  IntCmp $0 1 +2 0 0
+    Goto WriteLocalConfig
+    
+  ClearErrors
+  FileOpen $0 "$INSTDIR\apache2\conf\httpd.conf" "a"
+  IfErrors 0 +4
+    Push "write to the Apache configuration file"
+    Call ks_error
+    Return
+    
+  FileSeek $0 0 END
+  FileWrite $0 "$\r$\nInclude $\"../apps/${PRODUCT_SHORTNAME}/conf/httpd.conf$\"$\r$\n"
+  FileClose $0
+  
+  WriteLocalConfig:
+  
+  ClearErrors
+  CreateDirectory "$INSTDIR\apps\${PRODUCT_SHORTNAME}\conf"
+  IfErrors 0 +4
+    Push "create the configuration directory"
+    Call ks_error
+    Return
+    
+  ClearErrors
+  FileOpen $0 "$INSTDIR\apps\${PRODUCT_SHORTNAME}\conf\httpd.conf" "w"
+  IfErrors 0 +4
+    Push "write to the local configuration file"
+    Call ks_error
+    Return
+
+  FileWrite $0 "Alias /${PRODUCT_SHORTNAME} $\"../apps/${PRODUCT_SHORTNAME}/htdocs$\"$\r$\n$\r$\n"
+  FileWrite $0 "<Directory $\"../apps/${PRODUCT_SHORTNAME}/htdocs$\">$\r$\n"
+  FileWrite $0 "  Options -Indexes MultiViews FollowSymLinks$\r$\n"
+  FileWrite $0 "  AllowOverride All$\r$\n"
+  FileWrite $0 "  Order allow,deny$\r$\n"
+  FileWrite $0 "  Allow from all$\r$\n"
+  FileWrite $0 "</Directory>$\r$\n"
+  FileClose $0
+
+FunctionEnd
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/applist.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,112 @@
+/**
+ * Inserts an HTML file at the necessary point in applications.html.
+ * @param string HTML file
+ */
+
+Function BNRegisterApplicationToList
+  ClearErrors
+
+  ; Make sure it's not already in there
+  FileOpen $0 "$stack_instdir\apache2\htdocs\applications.html" "r"
+  IfErrors 0 +3
+    SetErrors
+    Return
+    
+  loop:
+    FileRead $0 $1
+    IfErrors EOF
+    Push $1
+    Push "Module ${PRODUCT_SHORTNAME}"
+    Call StrStr
+    Pop $1
+    StrCmp $1 "" +3
+      ; found it, skip write
+      FileClose $0
+      Return
+    Goto loop
+  EOF:
+  FileClose $0
+  
+  Pop $0
+  Push "$stack_instdir\apache2\htdocs\applications.html"
+  Push $0
+  Push "<!-- @@BITNAMI_MODULE_PLACEHOLDER@@ -->"
+  Call AppendBeforeSubstring
+FunctionEnd
+
+Function AppendBeforeSubstring
+  Pop $R2 ; marker
+  Pop $R1 ; file to insert
+  Pop $R0 ; file to modify
+  
+  StrCpy $R7 0 ; $R7 = current offset
+  
+  ClearErrors
+  FileOpen $R3 $R0 "a" ; $R3 = handle
+  FileSeek $R3 0
+  IfErrors 0 +3
+    SetErrors
+    Return
+    
+  loop:
+    FileRead $R3 $R4 ${NSIS_MAX_STRLEN} ; $R4 = line
+    IfErrors 0 +3
+      DetailPrint "EOF"
+      Goto EOF
+    StrLen $R8 $R4 ; $R8 = length of line
+    IntOp $R7 $R7 + $R8
+    
+    Push $R4
+    Push $R2
+    Call StrStr
+    Pop $R5 ; $R5 = substring test
+    StrCmp $R5 "" /* no match */ loop
+    
+    ; got a match!
+    StrLen $R6 $R5 ; Length of found substring
+    ; rewind a little bit, to right before the substring
+    IntOp $R8 $R7 - $R6
+    FileSeek $R3 -$R6 CUR $R5
+    
+    ; store the rest of the file
+    StrCpy $R9 ""
+    remainderloop:
+      ClearErrors
+      FileRead $R3 $R7
+      StrCpy $R9 "$R9$R7"
+      IfErrors 0 remainderloop
+    ; now jump back to our point
+    FileSeek $R3 $R5
+    
+    ; Now, write it all in
+    FileOpen $R4 $R1 "r"
+    IfErrors 0 +3
+      SetErrors
+      Return
+    loop2:
+      FileRead $R4 $R5 ${NSIS_MAX_STRLEN}
+      IfErrors EOF2
+      FileWrite $R3 $R5
+      Goto loop2
+      EOF2:
+        FileClose $R5
+      
+    FileWrite $R3 $R9
+  EOF:
+  FileClose $R3
+FunctionEnd
+
+Function enano_add_to_applist
+  StrCmp $PLUGINSDIR "" 0 +2
+    InitPluginsDir
+    
+  SetOutPath "$stack_instdir\apache2\htdocs\img"
+  File "gfx\enanocms-module.png"
+  SetOutPath "$PLUGINSDIR"
+  File "gfx\application.html"
+  Push "$PLUGINSDIR\application.html"
+  Call BNRegisterApplicationToList
+  IfErrors 0 +2
+    MessageBox MB_OK|MB_ICONEXCLAMATION "There was an error adding the application to the list."
+FunctionEnd
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/bitnamiutils.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,17 @@
+Function BNSetWAMPInstalledFlag
+  ClearErrors
+  ReadRegStr $wampstack_installed HKLM "Software\BitNami\BitNami WAMPStack" "Location"
+  IfErrors 0 +2
+    StrCpy $wampstack_installed 0
+
+  ClearErrors
+FunctionEnd
+
+Function BNSetWAPPInstalledFlag
+  ClearErrors
+  ReadRegStr $wappstack_installed HKLM "Software\BitNami\BitNami WAPPStack" "Location"
+  IfErrors 0 +2
+    StrCpy $wappstack_installed 0
+
+  ClearErrors
+FunctionEnd
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/core-files.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,15 @@
+!macro Core_Install
+  SetOverwrite try
+  SectionIn RO
+  
+  ; not a huge deal if this fails, it just helps me avoid dumb mistakes.
+  !system 'hg -R "${ENANO_ROOT}" update'
+  
+  SetOutPath "$INSTDIR\apps\${PRODUCT_SHORTNAME}\htdocs"
+  File /r /x .hg /x .hgtags "${ENANO_ROOT}"
+!macroend
+
+!macro Core_Uninstall
+  ; I'm sorry, but 1,000 files don't deserve to be listed out.
+  RmDir /r "$INSTDIR\apps\${PRODUCT_SHORTNAME}\htdocs"
+!macroend
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/dbal.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,27 @@
+!macro db_connect result user pass
+  Push "${user}"
+  Push "${pass}"
+  ClearErrors
+  StrCmp $db_driver "mysql" 0 +3
+    Call mysql_connect
+    Goto +2
+    Call postgresql_connect
+  Pop ${result}
+!macroend
+
+!define db_connect "!insertmacro db_connect"
+
+!macro db_create result user pass dbname nuser npass
+  Push "${user}"
+  Push "${pass}"
+  Push "${dbname}"
+  Push "${nuser}"
+  Push "${npass}"
+  StrCmp $db_driver "mysql" 0 +3
+    Call mysql_create_db
+    Goto +2
+    Call postgresql_create_db
+  Pop ${result}
+!macroend
+
+!define db_create "!insertmacro db_create"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/kickstart.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,61 @@
+; Now we're going to put the kickstart code into a separate file and try to keep it
+; as clean and human-readable as possible.
+
+!macro kickstart_var Var Value
+  ${str_replace} $1 "$$" "\$$" "${Value}"
+  FileWrite $0 "$$${Var} = <<<EOF$\r$\n$1$\r$\nEOF;$\r$\n$\r$\n"
+!macroend
+!macro kickstart_int Var Value
+  FileWrite $0 "$$${Var} = ${Value};$\r$\n"
+!macroend
+!define "kickstart_var" "!insertmacro kickstart_var"
+!define "kickstart_int" "!insertmacro kickstart_int"
+
+Function enano_write_kickstart_script
+  CreateDirectory "$INSTDIR\apps\enanocms\scripts"
+  ClearErrors
+  FileOpen $0 "$INSTDIR\apps\enanocms\scripts\kickstart.php" "w"
+  IfErrors 0 +4
+    Push "open the kickstart file"
+    Call ks_error
+    Return
+
+  FileWrite $0 "<?php$\r$\n// Automatically generated kickstart script.$\r$\n$\r$\n"
+
+  ${kickstart_int} "silent" "true"
+  ${kickstart_var} "lang_id" "eng"
+  ${kickstart_var} "scriptpath" "/${PRODUCT_SHORTNAME}"
+
+  ${kickstart_var} "driver" "$db_driver"
+  ${kickstart_var} "dbhost" "localhost"
+  ${kickstart_int} "dbport" "$db_port"
+  ${kickstart_var} "dbuser" "$db_user"
+  ${kickstart_var} "dbpasswd" "$db_password"
+  ${kickstart_var} "dbname" "$db_name"
+  ${kickstart_var} "db_prefix" "enano_"
+  ${kickstart_var} "user" "$enano_user"
+  ${kickstart_var} "pass" "$enano_password"
+  ${kickstart_var} "email" "$admin_email"
+  ${kickstart_var} "sitename" "$site_name"
+  ${kickstart_var} "sitedesc" "$site_desc"
+  ${kickstart_var} "copyright" "$site_copyright"
+  ${kickstart_var} "urlscheme" "$url_scheme"
+  ${kickstart_var} "start_with" "$start_with"
+  
+  FileWrite $0 "$\r$\nrequire(dirname(__FILE__) . '/../htdocs/install/includes/cli-core.php');"
+  FileClose $0
+
+FunctionEnd
+
+Function enano_run_kickstart_script
+  ; Debug :)
+  ; ExecWait '"$SYSDIR\notepad.exe" "$INSTDIR\apps\enanocms\scripts\kickstart.php"'
+  DetailPrint "Installing $(^Name) database"
+  nsExec::ExecToLog '"$INSTDIR\php\php.exe" "$INSTDIR\apps\enanocms\scripts\kickstart.php"'
+FunctionEnd
+
+Function ks_error
+  Pop $0
+  MessageBox MB_OK|MB_ICONEXCLAMATION "Setup failed to $0. You will need to install $(^Name) manually. To do this, navigate to:$\r$\n$\r$\n    http://localhost/apps/${PRODUCT_SHORTNAME}/$\r$\n$\r$\nYou will be presented with a screen that will allow you to continue the $(^Name) installation.$\r$\n$\r$\nYour database information is:$\r$\n$\r$\n  Server type: $db_dbmsname$\r$\n  Hostname: localhost$\r$\n  Port: $db_port$\r$\n  Database name: $db_name$\r$\n  Database user: $db_user$\r$\n  Database password: $db_password"
+  Abort "Could not $0!"
+FunctionEnd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/mysql.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,53 @@
+/**
+ * Verify credentials for a MySQL database. Assumes we are connecting to BitNami's DB.
+ * @param string Username
+ * @param string Password
+ * @return int 0 if successful, >0 on error. Will push an error string to the stack if >0.
+ */
+
+Function mysql_connect
+  Pop $R1 ; Password
+  Pop $R0 ; Username
+
+  SetOutPath $PLUGINSDIR
+  File "inst-resources\mysqlutil.php"
+
+  nsExec::ExecToLog '"$stack_instdir\php\php.exe" "$PLUGINSDIR\mysqlutil.php" $db_port "$R0" "$R1"'
+  Delete "$PLUGINSDIR\mysqlutil.php"
+  ; just be done; nsExec's result is on the top of the stack.
+FunctionEnd
+
+/**
+ * Create a MySQL database and grant privileges on it to the given user.
+ * @param string User to connect with
+ * @param string Password to connect with
+ * @param string Database name
+ * @param string New user
+ * @param string New user's password
+ */
+
+Function mysql_create_db
+  Pop $R5 ; Password
+  Pop $R4 ; User
+  Pop $R3 ; Database
+  Pop $R1 ; Password
+  Pop $R0 ; Username
+  
+  ReadINIStr $R2 "$stack_instdir\properties.ini" "MySQL" "mysql_root_directory"
+  IfFileExists "$R2\data\$R3" 0 DatabaseDoesNotExist
+    MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "The database $\"$R3$\" already exists. Do you want to delete and recreate it?$\n$\nIf you choose No, Setup will not alter MySQL's permissions, and you may need to set up permissions manually." IDYES +2
+      Return
+    
+  DatabaseDoesNotExist:
+  
+  SetOutPath $PLUGINSDIR
+  File "inst-resources\mysqlutil.php"
+  
+  nsExec::ExecToLog '"$stack_instdir\php\php.exe" "$PLUGINSDIR\mysqlutil.php" $db_port "$R0" "$R1" \
+                     "DROP DATABASE IF EXISTS `$R3`; \
+                      CREATE DATABASE `$R3`; \
+                      GRANT ALL PRIVILEGES ON `$R3`.* TO `$R4`@localhost \
+                        IDENTIFIED BY $\'$R5$\' WITH GRANT OPTION;"'
+  Delete "$PLUGINSDIR\mysqlutil.php"
+FunctionEnd
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/mysqlutil.php	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,31 @@
+<?php
+
+// MySQL utility script.
+
+if ( $argc < 2 )
+  die("Usage: {$argv[0]} port username password");
+
+$user = $argv[2];
+$pass = $argv[3];
+$handle = mysql_connect("localhost:{$argv[1]}", $user, $pass);
+if ( !$handle )
+{
+  echo "MySQL authentication failed.";
+  exit(1);
+}
+
+if ( !empty($argv[4]) )
+{
+  $queries = explode(';', $argv[4]);
+  foreach ( $queries as $query )
+  {
+    $query = trim($query);
+    if ( empty($query) )
+      continue;
+    echo "$query;\n";
+    if ( !mysql_query("$query;") )
+      exit(1);
+  }
+}
+
+exit(0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/postgresql.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,59 @@
+/**
+ * Verify credentials for a PostgreSQL database. Assumes we are connecting to BitNami's DB.
+ * @param string Username
+ * @param string Password
+ * @return int 0 if successful, >0 on error. Will push an error string to the stack if >0.
+ */
+
+!macro postgresql_get_bin_dir
+  StrCpy $R2 "$stack_instdir\postgresql\bin"
+!macroend
+
+Function postgresql_connect
+  Pop $R1 ; Password
+  Pop $R0 ; Username
+
+  SetOutPath $PLUGINSDIR
+  File "inst-resources\postgresqlutil.php"
+  
+  nsExec::ExecToLog '"$stack_instdir\php\php.exe" "$PLUGINSDIR\postgresqlutil.php" "$R0" "$R1"'
+  Delete "$PLUGINSDIR\postgresqlutil.php"
+  ; just be done; nsExec's result is on the top of the stack.
+FunctionEnd
+
+/**
+ * Create a postgresql database and grant privileges on it to the given user.
+ * @param string User to connect with
+ * @param string Password to connect with
+ * @param string Database name
+ * @param string New user
+ * @param string New user's password
+ */
+
+Function postgresql_create_db
+  Pop $R5 ; Password
+  Pop $R4 ; User
+  Pop $R3 ; Database
+  Pop $R1 ; Password
+  Pop $R0 ; Username
+
+  /*
+  ; This isn't a working feature in PostgreSQL.
+  IfFileExists "$stack_instdir\postgresql\data\$R3" 0 DatabaseDoesNotExist
+    MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "The database $\"$R3$\" already exists. Do you want to delete and recreate it?$\n$\nIf you choose No, Setup will not alter PostgreSQL's permissions, and you may need to set up permissions manually." IDYES +2
+      Return
+
+  DatabaseDoesNotExist:
+  */
+
+  SetOutPath $PLUGINSDIR
+  File "inst-resources\postgresqlutil.php"
+
+  nsExec::ExecToLog '"$stack_instdir\php\php.exe" "$PLUGINSDIR\postgresqlutil.php" "$R0" "$R1" \
+                     "DROP DATABASE IF EXISTS $R3; \
+                      DROP ROLE IF EXISTS $R4; \
+                      CREATE ROLE $R4 WITH PASSWORD $\'$R5$\' LOGIN; \
+                      CREATE DATABASE $R3 WITH OWNER $R4;"'
+  Delete "$PLUGINSDIR\postgresqlutil.php"
+FunctionEnd
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/postgresqlutil.php	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,31 @@
+<?php
+
+// PostgreSQL utility script.
+
+if ( $argc < 2 )
+  die("Usage: {$argv[0]} username password");
+
+$user = addslashes($argv[1]);
+$pass = addslashes($argv[2]);
+$handle = pg_connect("host=localhost port=5432 user='$user' password='$pass'");
+if ( !$handle )
+{
+  echo "PostgreSQL authentication failed.";
+  exit(1);
+}
+
+if ( !empty($argv[3]) )
+{
+  $queries = explode(';', $argv[3]);
+  foreach ( $queries as $query )
+  {
+    $query = trim($query);
+    if ( empty($query) )
+      continue;
+    echo "$query;\n";
+    if ( !pg_query("$query;") )
+      exit(1);
+  }
+}
+
+exit(0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/randompass.php	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,4 @@
+<?php
+$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+for ( $i = 0; $i < 8; $i++ )
+  echo $chars{ rand(0, strlen($chars)-1) };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inst-resources/str_replace.nsh	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,108 @@
+; StrReplace
+; Replaces all ocurrences of a given needle within a haystack with another string
+; Written by Dan Fuhry
+
+!ifndef _StrRep
+!define _StrRep
+
+Var sr_haystack
+Var sr_needle
+Var sr_replace
+Var sr_pos
+Var sr_needlelen
+Var sr_p_before
+Var sr_stacklen
+Var sr_p_after
+Var sr_newpos
+Var sr_test
+
+Function str_replace
+  Exch $sr_replace
+  Exch 1
+  Exch $sr_needle
+  Exch 2
+  Exch $sr_haystack
+    StrCpy $sr_pos -1
+    StrLen $sr_needlelen $sr_needle
+    StrLen $sr_stacklen $sr_haystack
+    loop:
+      IntOp $sr_pos $sr_pos + 1
+      StrCpy $sr_test $sr_haystack $sr_needlelen $sr_pos
+      StrCmp $sr_test $sr_needle found
+      StrCmp $sr_pos $sr_stacklen done
+      Goto loop
+    found:
+      StrCpy $sr_p_before $sr_haystack $sr_pos
+      IntOp $sr_newpos $sr_pos + $sr_needlelen
+      StrCpy $sr_p_after $sr_haystack "" $sr_newpos
+      StrCpy $sr_haystack $sr_p_before$sr_replace$sr_p_after
+      StrCpy $sr_pos $sr_newpos
+      StrLen $sr_stacklen $sr_haystack
+      Goto loop
+    done:
+  Pop $sr_needle ; Prevent "invalid opcode" errors and keep the
+  Pop $sr_needle ; stack as it was before the function was called
+  Exch $sr_haystack
+FunctionEnd
+
+!endif ; _StrRep
+
+!ifndef StrReplace
+  !macro _strReplaceConstructor OUT NEEDLE NEEDLE2 HAYSTACK
+    Push `${HAYSTACK}`
+    Push `${NEEDLE}`
+    Push `${NEEDLE2}`
+    Call str_replace
+    Pop `${OUT}`
+  !macroend
+
+  !define StrReplace '!insertmacro "_strReplaceConstructor"'
+  !define str_replace '!insertmacro "_strReplaceConstructor"'
+!endif
+
+; StrStr
+; input, top of stack = string to search for
+;        top of stack-1 = string to search in
+; output, top of stack (replaces with the portion of the string remaining)
+; modifies no other variables.
+;
+; Usage:
+;   Push "this is a long ass string"
+;   Push "ass"
+;   Call StrStr
+;   Pop $R0
+;  ($R0 at this point is "ass string")
+
+!macro StrStr un
+Function ${un}StrStr
+Exch $R1 ; st=haystack,old$R1, $R1=needle
+  Exch    ; st=old$R1,haystack
+  Exch $R2 ; st=old$R1,old$R2, $R2=haystack
+  Push $R3
+  Push $R4
+  Push $R5
+  StrLen $R3 $R1
+  StrCpy $R4 0
+  ; $R1=needle
+  ; $R2=haystack
+  ; $R3=len(needle)
+  ; $R4=cnt
+  ; $R5=tmp
+  loop:
+    StrCpy $R5 $R2 $R3 $R4
+    StrCmp $R5 $R1 done
+    StrCmp $R5 "" done
+    IntOp $R4 $R4 + 1
+    Goto loop
+done:
+  StrCpy $R1 $R2 "" $R4
+  Pop $R5
+  Pop $R4
+  Pop $R3
+  Pop $R2
+  Exch $R1
+FunctionEnd
+!macroend
+
+!insertmacro StrStr ""
+; !insertmacro StrStr "un."
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/licenses/GPL.txt	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/DatabaseConfig.ini	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,115 @@
+; Ini file generated by the HM NIS Edit IO designer.
+[Settings]
+NumFields=14
+
+[Field 1]
+Type=RadioButton
+Text=Create a database for me
+Left=16
+Right=-1
+Top=33
+Bottom=44
+State=1
+Flags=NOTIFY
+
+[Field 2]
+Type=RadioButton
+Text=Use an existing database
+Left=16
+Right=-1
+Top=73
+Bottom=84
+Flags=NOTIFY
+
+[Field 3]
+Type=Checkbox
+Text=Manually enter database name and login
+Flags=NOTIFY
+Left=16
+Right=-1
+Top=93
+Bottom=104
+
+[Field 4]
+Type=Password
+Left=96
+Right=176
+Top=54
+Bottom=67
+
+[Field 5]
+Type=Text
+Left=96
+Right=176
+Top=112
+Bottom=125
+
+[Field 6]
+Type=Text
+Left=96
+Right=176
+Top=132
+Bottom=145
+
+[Field 7]
+Type=Password
+Left=96
+Right=176
+Top=152
+Bottom=164
+
+[Field 8]
+Type=Password
+Left=96
+Right=176
+Top=171
+Bottom=184
+
+[Field 9]
+Type=Label
+Text=intro text will be filled here
+Left=0
+Right=-1
+Top=0
+Bottom=27
+
+[Field 10]
+Type=Label
+Text=Root password:
+Left=26
+Right=92
+Top=56
+Bottom=64
+
+[Field 11]
+Type=Label
+Text=Database name:
+Left=26
+Right=92
+Top=115
+Bottom=123
+
+[Field 12]
+Type=Label
+Text=Username:
+Left=26
+Right=92
+Top=134
+Bottom=142
+
+[Field 13]
+Type=Label
+Text=Password:
+Left=26
+Right=92
+Top=153
+Bottom=161
+
+[Field 14]
+Type=Label
+Text=Confirm password:
+Left=26
+Right=92
+Top=172
+Bottom=180
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/DatabaseConfig.nsi	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,163 @@
+!macro ShowRange hwnd low high value
+  !define tmp_id ${__LINE__}
+  StrCpy $R0 ${low}
+  loop.${tmp_id}:
+    GetDlgItem $R1 ${hwnd} $R0
+    ShowWindow $R1 ${value}
+    IntOp $R0 $R0 + 1
+    IntCmp $R0 ${high} loop.${tmp_id} loop.${tmp_id}
+    
+  !undef tmp_id
+!macroend
+!define ShowRange "!insertmacro ShowRange"
+
+Page custom DatabaseConfigCreate DatabaseConfigLeave " - Database configuration"
+
+Function DatabaseConfigCreate
+  StrCmp $XPUI_ABORTED 1 0 +2
+    Return
+  !insertmacro XPUI_INSTALLOPTIONS_EXTRACT_AS "pages\DatabaseConfig.ini" "DatabaseConfig.ini"
+  !insertmacro XPUI_HEADER_TEXT "Database configuration" "Configure how $(^Name) will access your database."
+  WriteINIStr "$PLUGINSDIR\DatabaseConfig.ini" "Field 9" "Text" \
+    "$(^Name) needs database access to work properly. Setup can create a database for you if you provide \
+     $db_dbmsname's administration password, or you can choose to enter credentials for a database that already exists."
+
+  !insertmacro XPUI_INSTALLOPTIONS_INITDIALOG "DatabaseConfig.ini"
+  Pop $XPUI_HWND
+
+  ${ShowRange} $XPUI_HWND 1204 1207 ${SW_HIDE}
+  ${ShowRange} $XPUI_HWND 1210 1213 ${SW_HIDE}
+
+  !insertmacro XPUI_INSTALLOPTIONS_SHOW
+FunctionEnd
+
+Function DatabaseConfigLeave
+  StrCmp $XPUI_ABORTED 1 0 +2
+    Return
+    
+  ReadINIStr $0 "$PLUGINSDIR\DatabaseConfig.ini" "Settings" "State"
+  StrCmp $0 1 RadioButtonClicked
+  StrCmp $0 2 RadioButtonClicked
+  StrCmp $0 3 UseManualClicked
+  Goto NextClicked
+  
+  RadioButtonClicked:
+    LockWindow on
+    ReadINIStr $0 "$PLUGINSDIR\DatabaseConfig.ini" "Field 1" "State"
+    IntCmp $0 0 SetUseExisting
+    
+      ; Show root password
+      GetDlgItem $0 $XPUI_HWND 1203
+      ShowWindow $0 ${SW_SHOW}
+      GetDlgItem $0 $XPUI_HWND 1209
+      ShowWindow $0 ${SW_SHOW}
+    
+      GetDlgItem $0 $XPUI_HWND 1202 ; Checkbox
+      SendMessage $0 ${BM_SETCHECK} ${BST_UNCHECKED} 0
+      EnableWindow $0 1
+      ${ShowRange} $XPUI_HWND 1204 1207 ${SW_HIDE}
+      ${ShowRange} $XPUI_HWND 1210 1213 ${SW_HIDE}
+      LockWindow off
+      Abort
+    
+    SetUseExisting:
+    
+      ; Hide root password
+      GetDlgItem $0 $XPUI_HWND 1203
+      ShowWindow $0 ${SW_HIDE}
+      GetDlgItem $0 $XPUI_HWND 1209
+      ShowWindow $0 ${SW_HIDE}
+      
+      GetDlgItem $0 $XPUI_HWND 1202 ; Checkbox
+      SendMessage $0 ${BM_SETCHECK} ${BST_CHECKED} 0
+      EnableWindow $0 0
+      ${ShowRange} $XPUI_HWND 1204 1207 ${SW_SHOW}
+      ${ShowRange} $XPUI_HWND 1210 1213 ${SW_SHOW}
+      LockWindow off
+      Abort
+    
+  UseManualClicked:
+    ReadINIStr $0 "$PLUGINSDIR\DatabaseConfig.ini" "Field 3" "State"
+    IntOp $0 $0 * ${SW_SHOW}
+    ${ShowRange} $XPUI_HWND 1204 1207 $0
+    ${ShowRange} $XPUI_HWND 1210 1213 $0
+    Abort
+  
+  NextClicked:
+
+    ; Figure out how we want to go about this.
+    StrCpy $db_needroot 0
+    ReadINIStr $0 "$PLUGINSDIR\DatabaseConfig.ini" "Field 1" "State"
+    IntCmp $0 0 UseCustomLogin
+    
+      ; Validate based on root password.
+      StrCpy $db_needroot 1
+      ReadINIStr $db_rootpass "$PLUGINSDIR\DatabaseConfig.ini" "Field 4" "State"
+      ${db_connect} $1 "$db_rootuser" "$db_rootpass"
+      IntCmp $1 0 +3
+        MessageBox MB_OK|MB_ICONEXCLAMATION "The $db_dbmsname root password you entered is incorrect. Please re-enter it."
+        Abort
+        
+      ; Does the user have their own credentials?
+      ReadINIStr $0 "$PLUGINSDIR\DatabaseConfig.ini" "Field 3" "State"
+      IntCmp $0 0 GenerateRandomLogin
+    
+    UseCustomLogin:
+    
+      ; Pull database settings from dialog
+      ReadINIStr $db_name "$PLUGINSDIR\DatabaseConfig.ini" "Field 5" "State"
+      ReadINIStr $db_user "$PLUGINSDIR\DatabaseConfig.ini" "Field 6" "State"
+      ReadINIStr $db_password "$PLUGINSDIR\DatabaseConfig.ini" "Field 7" "State"
+      ReadINIStr $R0 "$PLUGINSDIR\DatabaseConfig.ini" "Field 8" "State"
+      
+      ; Check password length
+      ; but don't if the user entered credentials that already exist
+      IntCmp $db_needroot 0 SkipLengthCheck
+        StrLen $R1 $R0
+        IntCmp $R1 6 +3 0 +3
+          MessageBox MB_OK|MB_ICONEXCLAMATION "Please choose a database password that is at least 6 characters in length."
+          Abort
+          
+      SkipLengthCheck:
+      ; Check password/confirm fields
+      StrCmp $db_password $R0 +3
+        MessageBox MB_OK|MB_ICONEXCLAMATION "The passwords you entered do not match. Please enter them again."
+        Abort
+        
+      ; If we're root, we can assume the login doesn't exist yet, so skip the validation
+      IntCmp $db_needroot 0 +2
+        Return
+        
+      ${db_connect} $R0 $db_user $db_password
+      IntCmp $R0 0 +3
+        ; Database auth failed
+        MessageBox MB_OK|MB_ICONEXCLAMATION "The username and password you entered are invalid. Please enter them again."
+        Abort
+        
+      ; This can be an error-prone process because entering credentials manually will keep
+      ; the installer from touching the database. If tables already exist, Enano's installer
+      ; will throw an error. Confirm this with the user.
+      MessageBox MB_YESNO|MB_ICONQUESTION "Do you really want to use manual database settings?$\r$\n\
+                                           $\r$\n\
+                                           Setup will not attempt to modify your existing database. If there is \
+                                           already an installation of $(^Name) in the database, the installer will \
+                                           fail. This option is recommended only for advanced users." IDYES +2
+        Abort ; on No
+      
+      Return
+      
+    GenerateRandomLogin:
+      StrCpy $db_name "bn_enanocms"
+      StrCpy $db_user "bn_enanocms"
+      Call GenerateRandomPassword
+      Pop $db_password
+      Return
+  
+FunctionEnd
+
+Function GenerateRandomPassword
+  SetOutPath $PLUGINSDIR
+  File "inst-resources\randompass.php"
+  nsExec::ExecToStack '"$stack_instdir\php\php.exe" "$PLUGINSDIR\randompass.php"'
+  Pop $R0
+FunctionEnd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/Login.ini	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,88 @@
+[Settings]
+NumFields=9
+
+;
+; Fields
+;
+
+; Username
+[Field 1]
+Type=Text
+Top=15
+Left=70
+Right=130
+Bottom=27
+
+; Password 1
+[Field 2]
+Type=Password
+Top=32
+Left=70
+Right=130
+Bottom=44
+
+; Password 2
+[Field 3]
+Type=Password
+Top=49
+Left=70
+Right=130
+Bottom=61
+
+; E-mail
+[Field 4]
+Type=Text
+Top=66
+Left=70
+Right=180
+Bottom=78
+
+;
+; Labels
+;
+
+; Username
+[Field 5]
+Type=Label
+Top=17
+Bottom=25
+Left=5
+Right=68
+Text=Username:
+
+; Password 1
+[Field 6]
+Type=Label
+Top=34
+Bottom=42
+Left=5
+Right=68
+Text=Password:
+
+; Password 2
+[Field 7]
+Type=Label
+Top=51
+Bottom=59
+Left=5
+Right=68
+Text=Confirm password:
+
+; E-mail
+[Field 8]
+Type=Label
+Top=68
+Bottom=76
+Left=5
+Right=69
+Text=E-mail address:
+
+; Header
+[Field 9]
+Type=Label
+Top=0
+Bottom=8
+Left=0
+Right=-1
+Text=Please enter your desired login details below. These will be used to administer your website.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/Login.nsi	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,34 @@
+Page custom CredentialsCreate CredentialsLeave " - Admin login"
+
+Function CredentialsCreate
+  !insertmacro XPUI_HEADER_TEXT "Create administrator" "Enter your desired username and password for administering your site."
+  !insertmacro XPUI_INSTALLOPTIONS_EXTRACT_AS "pages\Login.ini" "Login.ini"
+  !insertmacro XPUI_INSTALLOPTIONS_DISPLAY "Login.ini"
+FunctionEnd
+
+Function CredentialsLeave
+  StrCmp $XPUI_ABORTED "1" 0 +2
+    Return
+  
+  ReadIniStr $enano_user "$PLUGINSDIR\Login.ini" "Field 1" "State"
+  StrCmp $enano_user "" 0 +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Please enter a username."
+    Abort
+  
+  ReadIniStr $enano_password "$PLUGINSDIR\Login.ini" "Field 2" "State"
+  Strlen $0 $enano_password
+  IntCmp $0 6    +3  0  +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Please enter a password that is at least six characters long."
+    Abort
+    
+  ReadIniStr $0 "$PLUGINSDIR\Login.ini" "Field 3" "State"
+  StrCmp $0 $enano_password +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "The passwords you entered do not match. Please enter them again."
+    Abort
+    
+  ReadIniStr $admin_email "$PLUGINSDIR\Login.ini" "Field 4" "State"
+  StrCmp $admin_email "" 0 +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Please enter your e-mail address."
+    Abort
+FunctionEnd
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/SiteConfig.ini	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,110 @@
+; Ini file generated by the HM NIS Edit IO designer.
+[Settings]
+NumFields=13
+
+[Field 1]
+Type=Text
+State=Enano website
+Left=90
+Right=251
+Top=24
+Bottom=37
+
+[Field 2]
+Type=Text
+State=My first Enano website
+Left=90
+Right=251
+Top=44
+Bottom=57
+
+[Field 3]
+Type=Text
+State=© 2009 You. All rights reserved.
+Left=90
+Right=251
+Top=64
+Bottom=76
+
+[Field 4]
+Type=Checkbox
+Text=Enable search engine friendly URLs
+State=1
+Left=90
+Right=251
+Top=103
+Bottom=113
+
+[Field 5]
+Type=RadioButton
+Text=Install a blank website
+State=1
+Left=90
+Right=262
+Top=128
+Bottom=138
+
+[Field 6]
+Type=RadioButton
+Text=Install the Enano tutorial site
+Left=90
+Right=256
+Top=142
+Bottom=153
+
+[Field 7]
+Type=Label
+Text=Please enter some basic information about your Enano website.
+Left=0
+Right=-1
+Top=0
+Bottom=8
+
+[Field 8]
+Type=Label
+Text=Site name:
+Left=0
+Right=86
+Top=27
+Bottom=35
+
+[Field 9]
+Type=Label
+Text=Site description:
+Left=0
+Right=86
+Top=46
+Bottom=54
+
+[Field 10]
+Type=Label
+Text=Copyright notice:
+Left=0
+Right=86
+Top=65
+Bottom=73
+
+[Field 11]
+Type=Label
+Text=To make a copyright (©) symbol, hold down Alt and press the numbers 0169 on your NumPad.
+Left=90
+Right=-1
+Top=78
+Bottom=96
+
+[Field 12]
+Type=Label
+Text=Install website content:
+Left=0
+Right=86
+Top=128
+Bottom=136
+
+[Field 13]
+Type=Label
+Text=The Enano tutorial site provides a set of pages you can view and edit to learn how Enano works.
+Left=103
+Right=-1
+Top=157
+Bottom=175
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/SiteConfig.nsi	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,46 @@
+Page custom SiteConfigCreate SiteConfigLeave " - Configure site information"
+
+Function SiteConfigCreate
+  !insertmacro XPUI_INSTALLOPTIONS_EXTRACT_AS "pages\SiteConfig.ini" "SiteConfig.ini"
+  !insertmacro XPUI_HEADER_TEXT "Configure website" "Enter basic information about your website."
+  !insertmacro XPUI_INSTALLOPTIONS_DISPLAY "SiteConfig.ini"
+FunctionEnd
+
+Function SiteConfigLeave
+  StrCmp $XPUI_ABORTED 1 0 +2
+    Return
+    
+  ReadINIStr $site_name "$PLUGINSDIR\SiteConfig.ini" "Field 1" "State"
+  StrCmp $site_name "" 0 +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Please enter a name for your site."
+    Abort
+    
+  ReadINIStr $site_desc "$PLUGINSDIR\SiteConfig.ini" "Field 2" "State"
+  StrCmp $site_desc "" 0 +3
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Please enter a description for your site."
+    Abort
+    
+  ReadINIStr $site_copyright "$PLUGINSDIR\SiteConfig.ini" "Field 3" "State"
+  StrCmp $site_copyright "" 0 +2
+    StrCpy $site_copyright "No copyright assigned."
+    
+  Push $site_copyright
+  Call CleanCopyright
+  Pop $site_copyright
+  
+  StrCpy $url_scheme "standard"
+  ReadINIStr $0 "$PLUGINSDIR\SiteConfig.ini" "Field 4" "State"
+  IntCmp $0 1 0 +2 +2
+    StrCpy $url_scheme "short"
+    
+  StrCpy $start_with "blank"
+  ReadINIStr $0 "$PLUGINSDIR\SiteConfig.ini" "Field 6" "State"
+  IntCmp $0 1 0 +2 +2
+    StrCpy $start_with "tutorial"
+FunctionEnd
+
+Function CleanCopyright
+  Pop $0
+  ${str_replace} $0 "©" "&copy;" "$0"
+  Push $0
+FunctionEnd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/StackSelect.ini	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,30 @@
+; Ini file generated by the HM NIS Edit IO designer.
+[Settings]
+NumFields=3
+
+[Field 1]
+Type=RadioButton
+Text=WAMPStack (MySQL)
+State=1
+Left=32
+Right=-1
+Top=36
+Bottom=47
+
+[Field 2]
+Type=RadioButton
+Text=WAPPStack (PostgreSQL)
+State=0
+Left=32
+Right=-1
+Top=52
+Bottom=63
+
+[Field 3]
+Type=Label
+Text=Setup found both BitNami WAMPStack and BitNami WAPPStack on your server. Please select which one you would like to use:
+Left=0
+Right=-1
+Top=4
+Bottom=25
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pages/StackSelect.nsi	Wed May 27 01:05:23 2009 -0400
@@ -0,0 +1,83 @@
+Page custom StackSelectCreate StackSelectLeave " - Select stack"
+
+Function StackSelectCreate
+  ; Only show this page if both WAMPStack and WAPPStack are installed.
+  StrCmp $wampstack_installed 0 "" +3
+    Call StackSelectLeave
+    Return
+  StrCmp $wappstack_installed 0 "" +3
+    Call StackSelectLeave
+    Return
+  StrCmp $XPUI_ABORTED 1 "" +2
+    Abort
+    
+  !insertmacro XPUI_INSTALLOPTIONS_EXTRACT_AS "pages\StackSelect.ini" "StackSelect.ini"
+  !insertmacro XPUI_HEADER_TEXT "Select server stack" "Choose which BitNami stack installation you want to use to run $(^Name)."
+  !insertmacro XPUI_INSTALLOPTIONS_DISPLAY "StackSelect.ini"
+FunctionEnd
+
+Function StackSelectLeave
+  ; Here is where we make the final decision on which stack will be used.
+  IfFileExists "$PLUGINSDIR\StackSelect.ini" "" OnlyOneStackInstalled
+  
+    !macro ConfigCheck
+      IfFileExists "$stack_instdir\apps\${PRODUCT_SHORTNAME}\htdocs\config.php" 0 +3
+        MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Setup has found that $(^Name) is already installed on this stack. If you continue, the existing installation's configuration file will be deleted and your existing website will be replaced with a fresh one.$\n$\nDo you want to delete your existing $(^Name) website?" IDYES +2
+          Abort
+    !macroend
+  
+    ; Both stacks are installed; decide based on user selection
+    ReadINIStr $0 "$PLUGINSDIR\StackSelect.ini" "Field 1" "State"
+    StrCmp $0 1 "" UserSelectedWAPP
+      ; User selected WAMP
+      Call BNSetVarsForWAMP
+      !insertmacro ConfigCheck
+      Return
+      
+    UserSelectedWAPP:
+      ; User selected WAPP
+      Call BNSetVarsForWAPP
+      !insertmacro ConfigCheck
+      Return
+  
+  OnlyOneStackInstalled:
+  StrCmp $wampstack_installed 0 +3
+    ; MySQL
+    Call BNSetVarsForWAMP
+    !insertmacro ConfigCheck
+    Return
+    
+    ; PostgreSQL
+    Call BNSetVarsForWAPP
+    !insertmacro ConfigCheck
+    Return
+FunctionEnd
+
+Function BNSetVarsForWAMP
+  StrCpy $stack_type "WAMP"
+  StrCpy $stack_instdir "$wampstack_installed"
+  StrCpy $db_driver "mysql"
+  StrCpy $db_dbmsname "MySQL"
+  StrCpy $db_rootuser "root"
+  ReadINIStr $db_port "$stack_instdir\properties.ini" "MySQL" "mysql_port"
+  
+  StrCpy $stack_portbit ""
+  ReadINIStr $0 "$stack_instdir\properties.ini" "Apache" "apache_server_port"
+  StrCmp $0 "80" +2
+    StrCpy $stack_portbit ":$0"
+FunctionEnd
+
+Function BNSetVarsForWAPP
+  StrCpy $stack_type "WAPP"
+  StrCpy $stack_instdir "$wappstack_installed"
+  StrCpy $db_driver "postgresql"
+  StrCpy $db_dbmsname "PostgreSQL"
+  StrCpy $db_rootuser "postgres"
+  ; NOTE: WAPPStack doesn't record the port of PostgreSQL - we have to assume the default
+  StrCpy $db_port 5432
+  
+  StrCpy $stack_portbit ""
+  ReadINIStr $0 "$stack_instdir\properties.ini" "Apache" "apache_server_port"
+  StrCmp $0 "80" +2
+    StrCpy $stack_portbit ":$0"
+FunctionEnd
\ No newline at end of file