1 (* is_main.pas: Pascal Scripts routines for Inno Setup Windows installer.
2 * ====================================================================
3 * Copyright (c) 2000-2005 CollabNet. All rights reserved.
5 * This software is licensed as described in the file COPYING, which
6 * you should have received as part of this distribution. The terms
7 * are also available at http://subversion.tigris.org/license-1.html.
8 * If newer versions of this license are posted there, you may use a
9 * newer version instead, at your option.
11 * This software consists of voluntary contributions made by many
12 * individuals. For exact contribution history, see the revision
13 * history and logs, available at http://subversion.tigris.org/.
14 * ====================================================================
17 // ****************************************************************************
21 g_bMsVcpNotFound
: Boolean; // Visual C++ 6.0 Runtimes
22 g_bShFolderNotFound
: Boolean; // shfolder.dll
25 g_bHandleApache
: Boolean;
26 g_sApachePath
: String;
27 g_sApachePathBin
: String;
28 g_sApachePathConf
: String;
32 // Visual C++ 6.0 Runtime file related
33 FILE_MSVCPDLL
= 'msvcp60.dll';
34 URL_VCREDIST
= 'http://support.microsoft.com/support/kb/articles/Q259/4/03.ASP';
36 // shfolder.dll related
37 FILE_SHFOLDERDLL
= 'shfolder.dll';
38 URL_SHFREDIST
= 'http://download.microsoft.com/download/platformsdk/Redist/5.50.4027.300/W9XNT4/EN-US/shfinst.EXE';
41 REG_KEY_APACHE_SERVICE
= 'SYSTEM\CurrentControlSet\Services\Apache2';
42 APACHE_VER_MIN
= '{#= apache_ver_min}';
44 // Status codes for modules in httpd.conf
49 // ****************************************************************************
50 // Name: BackslashToSlash
51 // Purpose: Turning back slashes into slashes. This function is stolen
52 // shamelessly from the Inno help file.
53 // NOTE: For some unknown reason, this function has to stay here before
54 // other functions in order to avoid compile errors from the setup
55 // program. I don't not why, ..anyone?
56 function BackslashToSlash(const S
: String): String;
62 while I
<= Length(Result
) do
64 if Result
[I
] = '\' then
66 // Go to the next character. But do not simply increment I by 1.
67 // Increment by CharLength() in case Result[I] is a double-byte character.
68 I
:= I
+ CharLength(Result
, I
);
72 ///////////////////////////////////////////////////////////////////////////////
73 // APACHE related stuff
75 // ****************************************************************************
76 // Name: ApachePathParent
77 // Purpose: Returns the path of Apache parent folder.
78 function ApachePathParent(): String;
80 sApachePathParent
: String;
81 iLengthString
: Integer;
85 if RegKeyExists(HKLM
, REG_KEY_APACHE_SERVICE
) and UsingWinNT
then
87 // Set g_sApachePathBin
88 RegQueryStringValue(HKLM
, REG_KEY_APACHE_SERVICE
,
89 'ImagePath', sApachePathParent
);
91 // Remove the run command and strip quotes away from g_sApachePathBin
92 iPosK
:= Pos('-k', sApachePathParent
);
93 iLengthString
:= Length(sApachePathParent
);
94 Delete(sApachePathParent
, iLengthString
- (iLengthString
- iPosK
), iPosK
);
95 sApachePathParent
:= RemoveQuotes(sApachePathParent
);
97 // Strip basename twice so only the Apache parent path is left
98 sApachePathParent
:= ExtractFileDir(sApachePathParent
);
99 sApachePathParent
:= ExtractFileDir(sApachePathParent
);
102 // Function variables
103 Result
:= sApachePathParent
;
106 // ****************************************************************************
108 // Purpose: Decide if we should handle the Apache Server or not
109 function ApacheTask(): Boolean;
111 Result
:= UsingWinNT
and not (ApachePathParent
= '');
114 // ****************************************************************************
115 // Name: ApacheBinFound
116 // Purpose: Checks if bin\apache.exe excists in Apache's parent folder.
117 // Returns True if Yes and False if No
118 function ApacheBinFound(): Boolean;
120 sApacheBinary
: String;
122 sApacheBinary
:= ApachePathParent() + '\bin\apache.exe';
124 if FileExists(sApacheBinary
) then
132 // ****************************************************************************
133 // Name: ApacheServiceStop
134 // Purpose: Stopping the Apache Service
135 procedure ApacheServiceStop();
140 bRetVal
:= Exec('cmd.exe', '/C apache -k stop', g_sApachePathBin
,
141 SW_HIDE
, ewWaitUntilTerminated
, ErrorCode
);
144 // ****************************************************************************
145 // Name: ApacheServiceStart
146 // Purpose: Starting the Apache Service
147 procedure ApacheServiceStart();
152 bRetVal
:= Exec('cmd.exe', '/C apache -k start', g_sApachePathBin
,
153 SW_HIDE
, ewWaitUntilTerminated
, ErrorCode
);
157 // ****************************************************************************
158 // Name: ApacheModuleStatus
159 // Purpose: Identifying if a module is in a string and returning its status
160 Function ApacheModuleStatus(sLine
: String): Integer;
163 iPosSharp
, iPosModule
: Integer;
165 iStatus
:= STATUS_NONE
;
166 iPosSharp
:= Pos('#', sLine
);
167 iPosModule
:= Pos('LoadModule ', sLine
);
169 if Pos('foo_module ', sLine
) = 0 then
171 if (iPosSharp
> 0) and (iPosModule
> iPosSharp
) then
173 iStatus
:= STATUS_DISABLED
;
176 iStatus
:= STATUS_ENABLED
;
183 // ****************************************************************************
184 // Name: ApacheModuleName
185 // Purpose: Extracting and returning a module name from a string
186 Function ApacheModuleName(sLine
: String): String;
188 iPosModNameStart
, iPosModNameEnd
: Integer;
190 sModuleName
: String;
192 iPosModNameStart
:= (Pos('modules/mod_', sLine
) + 12);
193 iPosModNameEnd
:= (Pos('.so', sLine
) - 1);
196 iCharNum
:= iPosModNameStart
;
198 for iCharNum
:= iPosModNameStart
to iPosModNameEnd
do
200 sModuleName
:= sModuleName
+ StrGet(sLine
, iCharNum
);
203 sModuleName
:= sModuleName
+ '_module';
205 Result
:= sModuleName
;
208 // ****************************************************************************
209 // Name: ApacheConfFileEdit
210 // Purpose: Checking if the httpd.conf (Subversion related modules) file
212 procedure ApacheConfFileEdit(aHttpdConf
: TArrayOfString
;
213 iPosFileModules
, iPosFileModulesPost
,
214 iPosModDav
, iStatusModDav
,
215 iPosModDavSvn
, iStatusModDavSvn
,
216 iPosModAuthzSvn
, iStatusModAuthzSvn
: Integer);
218 sConfFileName
, sTimeString
: String;
219 sModuleDir
, sLoadModDav
, sLoadModDavSvn
, sLoadModAuthzSvn
: String;
222 sConfFileName
:= g_sApachePathConf
+ '\httpd.conf';
223 sTimeString
:= GetDateTimeString('yyyy/mm/dd hh:mm:ss', '-', ':');
225 sModuleDir
:= ExpandConstant('{app}');
226 sModuleDir
:= sModuleDir
+ '\bin';
227 sModuleDir
:= BackslashToSlash(sModuleDir
);
229 sLoadModDav
:= 'LoadModule dav_module modules/mod_dav.so';
230 sLoadModDavSvn
:= 'LoadModule dav_svn_module "' + sModuleDir
+ '/mod_dav_svn.so"';
231 sLoadModAuthzSvn
:= 'LoadModule authz_svn_module "' + sModuleDir
+ '/mod_authz_svn.so"';
233 //Backup the current httpd.conf
234 FileCopy (sConfFileName
, sConfFileName
+ '-svn-' + sTimeString
+ '.bak', False);
236 // Add the modules if they're not there
237 if (iStatusModDav
= STATUS_NONE
) then
239 if iPosModDav
= 0 then
241 iPosModDav
:= iPosFileModules
+ 10;
244 aHttpdConf
[iPosModDav
] := aHttpdConf
[iPosModDav
] + #13#10 + sLoadModDav
;
247 if (iStatusModDavSvn
= STATUS_NONE
) then
248 aHttpdConf
[iPosFileModulesPost
-1] := aHttpdConf
[iPosFileModulesPost
-1] + #13#10 +
251 if (iStatusModAuthzSvn
= STATUS_NONE
) then
252 aHttpdConf
[iPosFileModulesPost
-1] := aHttpdConf
[iPosFileModulesPost
-1] + #13#10 +
255 // Enable modules if disabled ********************************
256 if (iStatusModDav
= STATUS_DISABLED
) then
257 aHttpdConf
[iPosModDav
] := sLoadModDav
;
259 if (iStatusModDavSvn
= STATUS_DISABLED
) then
260 aHttpdConf
[iPosModDavSvn
] := sLoadModDavSvn
;
262 if (iStatusModAuthzSvn
= STATUS_DISABLED
) then
263 aHttpdConf
[iPosModAuthzSvn
] := sLoadModAuthzSvn
;
265 SaveStringsToFile(sConfFileName
, aHttpdConf
, False);
268 // ****************************************************************************
269 // Name: ApacheConfFileHandle
270 // Purpose: Checking if the httpd.conf (Subversion related modules) file should
271 // be edited and sets some data for further proccessing if needed.
272 procedure ApacheConfFileHandle();
274 aHttpdConf
: TArrayOfString
;
276 sConfFileName
: String;
277 sCurrentLine
: String;
279 iLineNum
, iArrayLen
: Integer;
281 iPosFileModules
, iPosFileModulesPost
: Integer;
282 iPosModDav
, iPosModDavSvn
, iPosModAuthzSvn
: Integer;
283 iStatusModDav
, iStatusModDavSvn
, iStatusModAuthzSvn
: Integer;
285 iStatusModDav
:= STATUS_NONE
;
286 iStatusModDavSvn
:= STATUS_NONE
;
287 iStatusModAuthzSvn
:= STATUS_NONE
;
289 sConfFileName
:= g_sApachePathConf
+ '\httpd.conf';
291 //Load the httpd.conf to the aHttpdConf array and init vars
292 LoadStringsFromFile(sConfFileName
, aHttpdConf
);
294 iArrayLen
:= GetArrayLength(aHttpdConf
)-1;
296 // Check httpd.conf line by line
297 for iLineNum
:= 0 to iArrayLen
do
299 sCurrentLine
:= aHttpdConf
[iLineNum
];
301 // Get module status and file data with help of the modules
302 if (Pos('LoadModule ', sCurrentLine
) > 0 ) then
304 if (ApacheModuleStatus(sCurrentLine
) > 0) then
306 if iPosFileModules
= 0 then
308 iPosFileModules
:= iLineNum
;
311 iPosFileModulesPost
:= iLineNum
+ 1;
314 //Decide placements and status of modules --------
316 // dav_module: If we (for some reason) don't find dav_module then
317 // we'll try to set the placement with help of cgi_module and make
318 // sure that we do it _before_ a dav_fs_module.
319 if ApacheModuleName(sCurrentLine
) = 'dav_module' then
321 iPosModDav
:= iLineNum
;
322 iStatusModDav
:= ApacheModuleStatus(sCurrentLine
);
325 if (ApacheModuleName(sCurrentLine
) = 'cgi_module') and
326 ((iStatusModDav
= STATUS_NONE
) and (iPosModDav
= 0)) then
327 iPosModDav
:= iLineNum
+ 1;
329 if (ApacheModuleName(sCurrentLine
) = 'dav_fs_module') and
330 (iStatusModDav
= STATUS_NONE
) then
331 iPosModDav
:= iLineNum
- 1;
334 if ApacheModuleName(sCurrentLine
) = 'dav_svn_module' then
336 iPosModDavSvn
:= iLineNum
;
337 iStatusModDavSvn
:= ApacheModuleStatus(sCurrentLine
);
341 if ApacheModuleName(sCurrentLine
) = 'authz_svn_module' then
343 iPosModAuthzSvn
:= iLineNum
;
344 iStatusModAuthzSvn
:= ApacheModuleStatus(sCurrentLine
);
349 // Edit httpd.conf if needed.
350 if (iStatusModDav
+ iStatusModDavSvn
+ iStatusModAuthzSvn
) <>
351 (STATUS_ENABLED
* 3) then
353 ApacheConfFileEdit (aHttpdConf
,
354 iPosFileModules
, iPosFileModulesPost
,
355 iPosModDav
, iStatusModDav
,
356 iPosModDavSvn
, iStatusModDavSvn
,
357 iPosModAuthzSvn
, iStatusModAuthzSvn
);
361 // ****************************************************************************
362 // Name: ApacheVersion
363 // Purpose: Returns apache.exe's version with the last number stripped.
364 function ApacheVersion(): String;
366 sApacheVersion
: String;
368 GetVersionNumbersString(g_sApachePathBin
+ '\apache.exe' ,sApacheVersion
);
369 Delete(sApacheVersion
, 7, 2);
370 Result
:= sApacheVersion
;
373 // ****************************************************************************
374 // Name: VerifyApache
375 // Purpose: Finding/Setting Apache paths and version info
376 procedure VerifyApache();
379 sApacheVersion
: String;
381 g_bHandleApache
:= True;
383 // Set/check the Apache paths
384 g_sApachePath
:= ApachePathParent
;
387 if g_sApachePathBin
= '' then
388 g_sApachePathBin
:= g_sApachePath
+ '\bin';
390 if not FileExists(g_sApachePathBin
+ '\apache.exe') then
392 sMsg
:= 'Could not find ''apache.exe'' in the system. Please, browse' +
393 ' to the folder where the Apache binary is.';
394 BrowseForFolder(sMsg
, g_sApachePathBin
, false);
398 if g_sApachePathConf
= '' then
399 g_sApachePathConf
:= g_sApachePath
+ '\conf';
401 if not FileExists(g_sApachePathConf
+ '\httpd.conf') then
403 sMsg
:= 'Could not find ''httpd.conf'' in the system. Please, browse' +
404 ' to the folder where configuration file is.';
405 BrowseForFolder(sMsg
, g_sApachePathConf
, false);
408 // Check that we have the required Apache version and warn the user if
410 sApacheVersion
:= ApacheVersion
;
412 if CompareStr(sApacheVersion
, APACHE_VER_MIN
) < 0 then
415 'WARNING: Apache http server version ' + sApacheVersion
+ ' is detected and the' + #13#10 +
416 'Subversion modules are built for the ' + APACHE_VER_MIN
+ ' version of the server.' + #13#10#13#10 +
417 'You are strongly encouraged to quit this setup and upgrade your' + #13#10 +
418 'apache server first, or go back to this setup''s ''Additional Tasks''' + #13#10 +
419 'dialog box and uncheck the task of installing the Apache modules.' + #13#10;
421 MsgBox(sMsg
, mbError
, MB_OK
);
425 ///////////////////////////////////////////////////////////////////////////////
426 // Misc. funtions used by the setup
428 // ****************************************************************************
429 // Name: ComponentList
430 // Purpose: In use for UninsHs when the user wants to uninstall/repair the
432 function ComponentList(Default
: string):string;
434 Result
:= WizardSelectedComponents(False);
437 // ****************************************************************************
438 // Name: ShFolderDllNotFound
439 // Purpose: Checks if FILE_SHFOLDERDLL does not exist.
440 // Returns True if missing and False if present.
441 function ShFolderDllNotFound(): Boolean;
445 sSysDir
:= ExpandConstant('{sys}');
447 if FileExists(sSysDir
+ '\' + FILE_SHFOLDERDLL
) then
449 g_bShFolderNotFound
:= False;
451 g_bShFolderNotFound
:= True;
454 Result
:= g_bShFolderNotFound
;
457 // ****************************************************************************
458 // Name: SysFilesDownLoadInfo
459 // Purpose: Informs the user about missing Windows system file(s).
460 Procedure SysFilesDownLoadInfo
;
470 sDocument
:= ' document';
472 if (g_bMsVcpNotFound
and g_bShFolderNotFound
) then
474 sSysfiles
:= FILE_MSVCPDLL
+ ' and ' + FILE_SHFOLDERDLL
;
477 sDocument
:= ' documents';
480 if (g_bMsVcpNotFound
and not g_bShFolderNotFound
) then
481 sSysfiles
:= FILE_MSVCPDLL
;
483 if (g_bShFolderNotFound
and not g_bMsVcpNotFound
) then
484 sSysfiles
:= FILE_SHFOLDERDLL
;
486 sMsg
:='The' + sFile
+ ' ' + sSysFiles
+ ' was not found in the system.' + #13#10#13#10 +
487 'Please, go to the Subversion entry in the Start Menu after the installation and' + #13#10 +
488 'read the ''Download and install''' + sDocument
+ ' for ' + sSysfiles
+ '.' + #13#10#13#10 +
489 'Subversion will not work without this' + sFile
+ '.' + #13#10#13#10;
491 MsgBox(sMsg
, mbInformation
, MB_OK
);
494 // ****************************************************************************
495 // Name: VCRuntimeNotFound
496 // Purpose: Checks if FILE_MSVCPDLL does not exist.
497 // Returns True if missing and False if present.
498 function VCRuntimeNotFound(): Boolean;
502 sSysDir
:= ExpandConstant('{sys}');
504 if FileExists(sSysDir
+ '\' + FILE_MSVCPDLL
) then
506 g_bMsVcpNotFound
:= False;
508 g_bMsVcpNotFound
:= True;
511 Result
:= g_bMsVcpNotFound
;
514 ///////////////////////////////////////////////////////////////////////////////
515 // Build in Inno Setup Pascal functions
516 // See Inno help file for usage about this functions.
518 // ****************************************************************************
519 // Name: InitializeSetup
520 // Purpose: Called during Setup's initialization.
521 // Return False to abort Setup, True otherwise.
522 function InitializeSetup(): Boolean;
524 //Initialize some global variables
525 g_bMsVcpNotFound
:= VCRuntimeNotFound
;
526 g_bShFolderNotFound
:= ShFolderDllNotFound
;
527 g_bHandleApache
:= False;
531 // ****************************************************************************
532 // Name: CurPageChanged
533 // Purpose: Called after a new wizard page (specified by CurPageID) is shown.
534 procedure CurPageChanged(CurStep
: Integer);
537 wpReady
: // Event after selected tasks
538 if IsTaskSelected('apachehandler') then
540 wpInstalling
: // Event before setup is copying destination files
541 if g_bHandleApache
then
549 // ****************************************************************************
550 // Name: CurStepChanged
551 // Purpose: Event function to perform pre- and post-install tasks.
552 procedure CurStepChanged(CurStep
: TSetupStep
);
554 if (CurStep
= ssPostInstall
) and g_bHandleApache
then
556 ApacheConfFileHandle
;
561 // ****************************************************************************
562 // Name: NextButtonClick
563 // Purpose: Called when the user clicks the Next button.
564 // If you return True, the wizard will move to the next page; if you
565 // return False, it will remain on the current page (specified by
567 function NextButtonClick(CurPage
: Integer): Boolean;
569 if (CurPage
= wpSelectComponents
) then
570 if (g_bMsVcpNotFound
or g_bShFolderNotFound
) then
571 SysFilesDownLoadInfo();
576 // ****************************************************************************
577 // Name: ShouldSkipPage
578 // Purpose: Event function to determine whether or not a particular page
579 // (specified by PageID) should be shown at all.
580 function ShouldSkipPage(CurPage
: Integer): Boolean;
582 // START In use by UninsHs
583 if Pos('/SP-', UpperCase(GetCmdTail
)) > 0 then
585 wpWelcome
, wpLicense
, wpPassword
, wpInfoBefore
, wpUserInfo
,
586 wpSelectDir
, wpSelectProgramGroup
, wpInfoAfter
:
589 // END In use by UninsHs