so Search.tsf and Search.rdf work
[freeside.git] / rt / bin / mason_handler.svc.in
1 #!@PERL@
2 # {{{ BEGIN BPS TAGGED BLOCK
3
4 # COPYRIGHT:
5 #  
6 # This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
7 #                                          <jesse@bestpractical.com>
8
9 # (Except where explicitly superseded by other copyright notices)
10
11
12 # LICENSE:
13
14 # This work is made available to you under the terms of Version 2 of
15 # the GNU General Public License. A copy of that license should have
16 # been provided with this software, but in any event can be snarfed
17 # from www.gnu.org.
18
19 # This work is distributed in the hope that it will be useful, but
20 # WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 # General Public License for more details.
23
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
28
29 # CONTRIBUTION SUBMISSION POLICY:
30
31 # (The following paragraph is not intended to limit the rights granted
32 # to you to modify and distribute this software under the terms of
33 # the GNU General Public License and is only of importance to you if
34 # you choose to contribute your changes and enhancements to the
35 # community by submitting them to Best Practical Solutions, LLC.)
36
37 # By intentionally submitting any modifications, corrections or
38 # derivatives to this work, or any other work intended for use with
39 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
40 # you are the copyright holder for those contributions and you grant
41 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
42 # royalty-free, perpetual, license to use, copy, create derivative
43 # works based on those contributions, and sublicense and distribute
44 # those contributions and any derivatives thereof.
45
46 # }}} END BPS TAGGED BLOCK
47 =head1 NAME
48
49 mason_handler.svc - Win32 IIS Service handler for RT
50
51 =head1 SYNOPSIS
52
53     perl mason_handler.svc --install    # install as service
54     perl mason_handler.svc --deinstall  # deinstall this service
55     perl mason_handler.svc --help       # show this help
56     perl mason_handler.svc              # launch handler from command line
57
58 =head1 DESCRIPTION
59
60 This script manages a stand-alone FastCGI server, and populates the necessary
61 registry settings to run it with Microsoft IIS Server 4.0 or above.
62
63 Before running it, you need to install the B<FCGI> module from CPAN, as well as
64 B<Win32::Daemon> from L<http://www.roth.net/perl/Daemon/> if you want to install
65 itself as a service.
66
67 This script will automatically create a virtual directory under the IIS root;
68 its name is taken from C<$WebPath> in the F<RT_Config.pm> file.  Additionally,
69 please install the ISAPI binary from L<http://www.caraveo.com/fastcgi/> and set
70 up an ISAPI Script Map that maps F<.html> files to F<isapi_fcgi.dll>.
71
72 Once the service is launched (either via C<net start RTFastCGI> or by running
73 C<perl mason_handler.svc>), a FCGI server will start and bind to port C<8284>
74 (mnemonics: the ASCII value of C<R> and C<T>); the ISAPI handler's C<BindPath>
75 registry setting will also be automatically populated.
76
77 =cut
78
79 package RT::Mason;
80
81 use strict;
82 use File::Basename;
83 use vars '$Handler';
84 require (dirname(__FILE__) . '/webmux.pl');
85
86 use Cwd;
87 use File::Spec;
88
89 use Win32;
90 use Win32::Process;
91 use Win32::Service;
92 use Win32::TieRegistry;
93
94 my $ProcessObj;
95
96 BEGIN {
97     my $runsvc = sub {
98         Win32::Process::Create(
99             $ProcessObj, $^X, "$^X $0 --run", 0, NORMAL_PRIORITY_CLASS, "."
100         ) or do {
101             die Win32::FormatMessage( Win32::GetLastError() );
102         };
103
104         chdir File::Basename::dirname($0);
105         my $path = Cwd::cwd();
106         $path =~ s|/|\\|g;
107         $path =~ s|bin$|share\\html|;
108
109         $Win32::TieRegistry::Registry->{
110             'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\'.
111             'W3SVC\Parameters\Virtual Roots\\'
112         }->{$RT::WebPath || '/'} = "$path,,205";
113             
114         $Win32::TieRegistry::Registry->{
115             'HKEY_LOCAL_MACHINE\Software\FASTCGI\.html\\'
116         }->{'BindPath'} = $ENV{'FCGI_SOCKET_PATH'};
117
118         Win32::Service::StartService(Win32::NodeName, 'W3SVC');
119     };
120     
121     if ($ARGV[0] eq '--deinstall') {
122         chdir File::Basename::dirname($0);
123         my $path = Cwd::cwd();
124         $path =~ s|/|\\|g;
125
126         require Win32::Daemon;
127         Win32::Daemon::DeleteService('RTFastCGI');
128         warn "Service 'RTFastCGI' successfully deleted.\n";
129         exit;
130     }
131     elsif ($ARGV[0] eq '--install') {
132         chdir File::Basename::dirname($0);
133         my $path = Cwd::cwd();
134         $path =~ s|/|\\|g;
135
136         require Win32::Daemon;
137         Win32::Daemon::DeleteService('RTFastCGI');
138         
139         my $rv = Win32::Daemon::CreateService( {
140             machine =>  '',
141             name    =>  'RTFastCGI',
142             display =>  'RT FastCGI Handler',
143             path    =>  $^X,
144             user    =>  '',
145             pwd     =>  $path,
146             description => 'Enables port 8284 as the RT FastCGI handler.',
147             parameters  => File::Spec->catfile(
148                     $path, File::Basename::basename($0)
149             ) . ' --service',
150         } );
151     
152         if ($rv) {
153             warn "Service 'RTFastCGI' successfully created.\n";
154         }
155         else {
156             warn "Failed to add service: " . Win32::FormatMessage(
157                 Win32::Daemon::GetLastError()
158             ) . "\n";
159         }
160         exit;
161     }
162     elsif ($ARGV[0] eq '--service') {
163         require Win32::Daemon;
164
165         my $PrevState = Win32::Daemon::SERVICE_START_PENDING();
166         Win32::Daemon::StartService() or die $^E;
167
168         while ( 1 ) {
169             my $State = Win32::Daemon::State();
170             last if $State == Win32::Daemon::SERVICE_STOPPED();
171             
172             if ( $State == Win32::Daemon::SERVICE_START_PENDING() ) {
173                 $runsvc->();
174                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
175                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
176             }
177             elsif ( $State == Win32::Daemon::SERVICE_CONTINUE_PENDING() ) {
178                 $ProcessObj->Resume;
179                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
180                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
181             }
182             elsif ( $State == Win32::Daemon::SERVICE_STOP_PENDING() ) {
183             $ProcessObj->Kill(0);
184                 Win32::Daemon::State( Win32::Daemon::SERVICE_STOPPED() );
185                 $PrevState = Win32::Daemon::SERVICE_STOPPED();
186             }
187             elsif ( $State == Win32::Daemon::SERVICE_RUNNING() ) {
188                 my $Message = Win32::Daemon::QueryLastMessage(1);
189                 if ( $Message == Win32::Daemon::SERVICE_CONTROL_INTERROGATE() ) {
190                     Win32::Daemon::State( $PrevState );
191                 }
192                 elsif ( $Message == Win32::Daemon::SERVICE_CONTROL_SHUTDOWN() ) {
193                     Win32::Daemon::State( Win32::Daemon::SERVICE_STOP_PENDING(), 15000 );
194                 }
195                 elsif ( $Message != Win32::Daemon::SERVICE_CONTROL_NONE() ) {
196                     Win32::Daemon::State( $PrevState );
197                 }
198             }
199             
200             Win32::Sleep( 1000 );
201         }
202                 
203         Win32::Daemon::StopService();
204         exit;
205     }
206     elsif ($ARGV[0] eq '--help') {
207         system("perldoc $0");
208         exit;
209     }
210     elsif ($ARGV[0] ne '--run') {
211         $SIG{__DIE__} = sub { $ProcessObj->Kill(0) if $ProcessObj };
212         $runsvc->();
213         warn "RT FastCGI Handler launched. Press [Enter] to terminate...\n";
214         <STDIN>;
215         exit;
216     }
217 }
218
219 ###############################################################################
220
221 warn "Begin listening on $ENV{'FCGI_SOCKET_PATH'}\n";
222
223 require CGI::Fast;
224
225 RT::Init();
226
227 # Response loop
228 while( my $cgi = CGI::Fast->new ) {
229     my $comp = $ENV{'PATH_INFO'};
230
231     $comp = $1 if ($comp =~ /^(.*)$/);
232     $comp =~ s|^$RT::WebPath\b||i;
233     $comp .= "index.html" if ($comp =~ /\/$/);
234     $comp =~ s/.pl$/.html/g;
235     
236     warn "Serving $comp\n";
237
238     $Handler->handle_cgi($comp);
239     # _should_ always be tied
240 }
241
242 1;
243
244 =head1 AUTHORS
245
246 Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
247
248 =head1 COPYRIGHT
249
250 Copyright 2002 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.
251
252 This program is free software; you can redistribute it and/or 
253 modify it under the same terms as Perl itself.
254
255 See L<http://www.perl.com/perl/misc/Artistic.html>
256
257 =cut