import rt 3.4.6
[freeside.git] / rt / lib / RT.pm.in
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4 #  
5 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
6 #                                          <jesse@bestpractical.com>
7
8 # (Except where explicitly superseded by other copyright notices)
9
10
11 # LICENSE:
12
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27
28 # CONTRIBUTION SUBMISSION POLICY:
29
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
35
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
44
45 # END BPS TAGGED BLOCK }}}
46 package RT;
47 use strict;
48 use RT::I18N;
49 use RT::CurrentUser;
50 use RT::System;
51
52 use vars qw($VERSION $System $SystemUser $Nobody $Handle $Logger
53         $CORE_CONFIG_FILE
54         $SITE_CONFIG_FILE
55         $BasePath
56         $EtcPath
57         $VarPath
58         $LocalPath
59         $LocalEtcPath
60         $LocalLexiconPath
61         $LogDir
62         $BinPath
63         $MasonComponentRoot
64         $MasonLocalComponentRoot
65         $MasonDataDir
66         $MasonSessionDir
67 );
68
69 $VERSION = '@RT_VERSION_MAJOR@.@RT_VERSION_MINOR@.@RT_VERSION_PATCH@';
70 $CORE_CONFIG_FILE = "@CONFIG_FILE_PATH@/RT_Config.pm";
71 $SITE_CONFIG_FILE = "@CONFIG_FILE_PATH@/RT_SiteConfig.pm";
72
73 @DATABASE_ENV_PREF@
74
75 $BasePath = '@RT_PATH@';
76
77 $EtcPath = '@RT_ETC_PATH@';
78 $BinPath = '@RT_BIN_PATH@';
79 $VarPath = '@RT_VAR_PATH@';
80 $LocalPath = '@RT_LOCAL_PATH@';
81 $LocalEtcPath = '@LOCAL_ETC_PATH@';
82 $LocalLexiconPath = '@LOCAL_LEXICON_PATH@';
83
84 # $MasonComponentRoot is where your rt instance keeps its mason html files
85
86 $MasonComponentRoot = '@MASON_HTML_PATH@';
87
88 # $MasonLocalComponentRoot is where your rt instance keeps its site-local
89 # mason html files.
90
91 $MasonLocalComponentRoot = '@MASON_LOCAL_HTML_PATH@';
92
93 # $MasonDataDir Where mason keeps its datafiles
94
95 $MasonDataDir = '@MASON_DATA_PATH@';
96
97 # RT needs to put session data (for preserving state between connections
98 # via the web interface)
99 $MasonSessionDir = '@MASON_SESSION_PATH@';
100
101
102
103 =head1 NAME
104
105 RT - Request Tracker
106
107 =head1 SYNOPSIS
108
109 A fully featured request tracker package
110
111 =head1 DESCRIPTION
112
113 =head2 LoadConfig
114
115 Load RT's config file.  First, the site configuration file
116 (C<RT_SiteConfig.pm>) is loaded, in order to establish overall site
117 settings like hostname and name of RT instance.  Then, the core
118 configuration file (C<RT_Config.pm>) is loaded to set fallback values
119 for all settings; it bases some values on settings from the site
120 configuration file.
121
122 In order for the core configuration to not override the site's
123 settings, the function C<Set> is used; it only sets values if they
124 have not been set already.
125
126 =cut
127
128 sub LoadConfig {
129      local *Set = sub { $_[0] = $_[1] unless defined $_[0] }; 
130     if ( -f "$SITE_CONFIG_FILE" ) {
131         require $SITE_CONFIG_FILE
132           || die ("Couldn't load RT config file  '$SITE_CONFIG_FILE'\n$@");
133     }
134     require $CORE_CONFIG_FILE
135       || die ("Couldn't load RT config file '$CORE_CONFIG_FILE'\n$@");
136     RT::I18N->Init;
137 }
138
139 =head2 Init
140
141 Conenct to the database, set up logging.
142
143 =cut
144
145 sub Init {
146
147     #Get a database connection
148     ConnectToDatabase();
149
150     #RT's system user is a genuine database user. its id lives here
151     $SystemUser = new RT::CurrentUser();
152     $SystemUser->LoadByName('RT_System');
153     
154     #RT's "nobody user" is a genuine database user. its ID lives here.
155     $Nobody = new RT::CurrentUser();
156     $Nobody->LoadByName('Nobody');
157   
158     $System = RT::System->new();
159
160     InitClasses();
161     InitLogging(); 
162 }
163
164   
165 =head2 ConnectToDatabase
166
167 Get a database connection
168
169 =cut
170
171 sub ConnectToDatabase {
172     require RT::Handle;
173     unless ($Handle && $Handle->dbh && $Handle->dbh->ping) {
174         $Handle = RT::Handle->new();
175     } 
176     $Handle->Connect();
177 }
178     
179 =head2 InitLogging
180
181 Create the RT::Logger object. 
182
183 =cut
184
185 sub InitLogging {
186
187     # We have to set the record separator ($, man perlvar)
188     # or Log::Dispatch starts getting
189     # really pissy, as some other module we use unsets it.
190
191     $, = '';
192     use Log::Dispatch 1.6;
193
194     unless ($RT::Logger) {
195
196     $RT::Logger=Log::Dispatch->new();
197     
198     if ($RT::LogToFile) {
199         my ($filename, $logdir);
200         if ($RT::LogToFileNamed =~ m![/\\]!) {
201             # looks like an absolute path.
202             $filename = $RT::LogToFileNamed;
203             ($logdir) = $RT::LogToFileNamed =~ m!^(.*[/\\])!;
204         }
205         else {
206             $filename = "$RT::LogDir/$RT::LogToFileNamed";
207             $logdir = $RT::LogDir;
208         }
209
210     unless ( -d $logdir && ( ( -f $filename && -w $filename ) || -w $logdir ) ) {
211         # localizing here would be hard when we don't have a current user yet
212         # die $self->loc("Log directory [_1] not found or couldn't be written.\n RT can't run.", $RT::LogDir);
213         die ("Log file $filename couldn't be written or created.\n RT can't run.");
214     }
215
216     package Log::Dispatch::File;
217     require Log::Dispatch::File;
218
219
220           $RT::Logger->add(Log::Dispatch::File->new
221                        ( name=>'rtlog',
222                          min_level=> $RT::LogToFile,
223                          filename=> $filename,
224                          mode=>'append',
225                          callbacks => sub { my %p = @_;
226                                 my ($package, $filename, $line) = caller(5);
227                                 return "[".gmtime(time)."] [".$p{level}."]: $p{message} ($filename:$line)\n"}
228              
229              
230              
231                        ));
232     }
233     if ($RT::LogToScreen) {
234         package Log::Dispatch::Screen;
235         require Log::Dispatch::Screen;
236         $RT::Logger->add(Log::Dispatch::Screen->new
237                      ( name => 'screen',
238                        min_level => $RT::LogToScreen,
239                          callbacks => sub { my %p = @_;
240                                 my ($package, $filename, $line) = caller(5);
241                                 return "[".gmtime(time)."] [".$p{level}."]: $p{message} ($filename:$line)\n"
242                                 },
243              
244                        stderr => 1
245                      ));
246     }
247     if ($RT::LogToSyslog) {
248         package Log::Dispatch::Syslog;
249         require Log::Dispatch::Syslog;
250         $RT::Logger->add(Log::Dispatch::Syslog->new
251                      ( name => 'syslog',
252                        ident => 'RT',
253                        min_level => $RT::LogToSyslog,
254                          callbacks => sub { my %p = @_;
255                                 my ($package, $filename, $line) = caller(5);
256
257                                 # syswrite() cannot take utf8; turn it off here.
258                                 Encode::_utf8_off($p{message});
259
260                                 if ($p{level} eq 'debug') {
261
262                                 return "$p{message}\n" }
263                                 else {
264                                 return "$p{message} ($filename:$line)\n"}
265                                 },
266              
267                        stderr => 1,
268                @RT::LogToSyslogConf
269                      ));
270     }
271
272     }
273
274 # {{{ Signal handlers
275
276 ## This is the default handling of warnings and die'ings in the code
277 ## (including other used modules - maybe except for errors catched by
278 ## Mason).  It will log all problems through the standard logging
279 ## mechanism (see above).
280
281 $SIG{__WARN__} = sub {
282     my $w = shift;
283     $w =~ s/(?:\r*\n)+$//;
284     # The 'wide character' warnings has to be silenced for now, at least
285     # until HTML::Mason offers a sane way to process both raw output and
286     # unicode strings.
287     $RT::Logger->warning($w) if index($w, 'Wide character in ') != 0;
288 };
289
290 #When we call die, trap it and log->crit with the value of the die.
291
292 $SIG{__DIE__}  = sub {
293     unless ($^S || !defined $^S ) {
294         $RT::Handle->Rollback();
295         $RT::Logger->crit("$_[0]");
296     }
297     die $_[0];
298 };
299
300 # }}}
301
302 }
303
304 =head2 InitClasses
305
306 Load all modules that define base classes
307
308 =cut
309
310 sub InitClasses {
311     require RT::Tickets;
312     require RT::Transactions;
313     require RT::Users;
314     require RT::CurrentUser;
315     require RT::Templates;
316     require RT::Queues;
317     require RT::ScripActions;
318     require RT::ScripConditions;
319     require RT::Scrips;
320     require RT::Groups;
321     require RT::GroupMembers;
322     require RT::CustomFields;
323     require RT::CustomFieldValues;
324     require RT::ObjectCustomFields;
325     require RT::ObjectCustomFieldValues;
326 }
327
328 # }}}
329
330
331 sub SystemUser {
332     return($SystemUser);
333 }       
334
335 sub Nobody {
336     return ($Nobody);
337 }
338
339 =head1 BUGS
340
341 Please report them to rt-bugs@fsck.com, if you know what's broken and have at least 
342 some idea of what needs to be fixed.
343
344 If you're not sure what's going on, report them rt-devel@lists.bestpractical.com.
345
346 =head1 SEE ALSO
347
348 L<RT::StyleGuide>
349 L<DBIx::SearchBuilder>
350
351 =begin testing
352
353 ok ($RT::Nobody->Name() eq 'Nobody', "Nobody is nobody");
354 ok ($RT::Nobody->Name() ne 'root', "Nobody isn't named root");
355 ok ($RT::SystemUser->Name() eq 'RT_System', "The system user is RT_System");
356 ok ($RT::SystemUser->Name() ne 'noname', "The system user isn't noname");
357
358 =end testing
359
360 =cut
361
362 eval "require RT_Local";
363 die $@ if ($@ && $@ !~ qr{^Can't locate RT_Local.pm});
364
365 1;