"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "wormscan-1.6.1-src/net/websoup/wormscan/Program.java" of archive wormscan-1.6.1-src.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 package net.websoup.wormscan;
2
3 /*
4 * This file is part of WormScan.
5 *
6 * WormScan is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 import java.io.*;
22 import java.net.InetAddress;
23 import java.text.SimpleDateFormat;
24 import java.util.Locale;
25 import java.util.Date;
26 import java.util.Vector;
27 import java.util.Map;
28 import java.util.TreeMap;
29 import java.util.Enumeration;
30 import java.util.Collection;
31 import java.util.Iterator;
32 import java.util.Properties;
33 import java.util.Stack;
34
35 import org.apache.oro.text.perl.Perl5Util;
36 import org.apache.oro.text.regex.Perl5Compiler;
37 import org.apache.oro.text.regex.Perl5Matcher;
38 import org.apache.oro.text.regex.Pattern;
39 import org.apache.oro.text.regex.MatchResult;
40 import org.apache.tools.bzip2.CBZip2InputStream;
41 import org.apache.velocity.VelocityContext;
42 import org.apache.velocity.Template;
43 import org.apache.velocity.app.Velocity;
44
45 import java.util.zip.GZIPInputStream;
46 import java.util.zip.GZIPOutputStream;
47
48 import net.websoup.wormscan.*;
49 import net.websoup.utility.FilenameResolver;
50
51 import org.jfree.chart.*;
52 import org.jfree.chart.plot.*;
53 import org.jfree.chart.ui.*;
54 import org.jfree.data.*;
55 import org.jfree.data.time.*;
56 import org.jfree.ui.*;
57
58 /**
59 * Title: WormScan
60 * Description: Extendable system to parse web server log files and output reports on attack attempts by various known internet worms.
61 * Copyright: Copyright (c) 2001-2004 Andriy Rozeluk <arozeluk@websoup.net>
62 * @author Andriy Rozeluk
63 * @version 1.6.1
64 */
65
66 public class Program extends Thread {
67 private static int bufferSize = 32768;
68
69 private static final int GZIP_BUFFER = 8192;
70
71 /* how many parser threads to run */
72 private static int NUM_PARSE_THREADS = 1;
73
74 /* current line being processed by this thread */
75 private String currentLine;
76
77 /* identify this thread by a unique number */
78 private int threadID;
79
80 /* our logfile reader */
81 private BufferedReader reader;
82
83 /* the imported worms */
84 private static Worm[] worms;
85
86 /* store our list of attacks here */
87 private static Vector attackStorage;
88
89 /* what size to initialize our attackStorage to */
90 private static int INITIAL_ATTACK_STORAGE_SIZE = 10000;
91
92 /* store our list of hosts here */
93 private static Map sourceStorage;
94
95 /* what size to initialize our sourceStorage to */
96 private static int INITIAL_SOURCE_STORAGE_SIZE = 4000;
97
98 /* save DNS information in file cache [Y/N]*/
99 private static boolean cacheDNS = true;
100
101 /* all filenames of reports will start with this */
102 private static String BASE_FILENAME = "wormreport";
103
104 /* all filenames of reports will end with this */
105 private static String BASE_EXTENSION = ".html";
106
107 /* template to load for detailed report generation */
108 private static String REPORT_TEMPLATE_NAME = "wormreport.vm";
109
110 /* template to load for summary report generation */
111 private static String SUMMARY_TEMPLATE_NAME = "wormsummary.vm";
112
113 /* filename to store number of attacks in */
114 private static String NUM_ATTACKS_FILE = null;
115
116 /* filename to store DNS cache in */
117 private static String DNS_CACHE_FILENAME = "dnscache";
118
119 /* show only latest attack by host in generated reports */
120 private static boolean SHOW_LATEST_ATTACK_ONLY = true;
121
122 /* output GZIP-compressed version of reports while we're at it */
123 private static boolean WRITE_GZIP = true;
124
125 /* go ahead and check to see if log files are GZIP-compressed before parsing */
126 private static boolean CHECK_GZIP = true;
127
128 /* go ahead and check to see if log files are BZIP2-compressed before parsing */
129 private static boolean CHECK_BZIP2 = true;
130
131 /* go ahead and resolve hostnames */
132 static boolean RESOLVE_DNS = true;
133
134 /* how much information should we give the console? */
135 static int OUTPUT_LEVEL = 3;
136
137 /* how many sort threads to run simultaneously */
138 private static int NUM_RUNNING_SORT_THREADS = 1;
139
140 private static String CHART_BASE_FILENAME = "chart";
141 private static int CHART_WIDTH = 640;
142 private static int CHART_HEIGHT = 480;
143 private static boolean CHARTS_PRODUCE = false;
144
145 private Perl5Matcher matcher;
146
147 /* how many resolver threads to run */
148 private static int NUM_RESOLVER_THREADS = 1;
149
150 private static Resolver[] resolverThreads;
151
152 private static Perl5Compiler p5 = new Perl5Compiler();
153 private static Pattern pattern;
154 private static int patternHostIndex = 1;
155 private static int patternDateIndex = 3;
156 private static Locale LOG_LOCALE = Locale.US;
157 private static String defaultDatePattern = "d/MMM/yyy:H:mm:ss";
158 private static SimpleDateFormat patternDateFormat = new SimpleDateFormat(defaultDatePattern, LOG_LOCALE);
159 private static int patternUriIndex = 6;
160 private static boolean patternPrependFilenameToDate = false;
161
162 /* get a bunch of threads ready to resolve hostnames. They'll wait */
163 private static boolean resolveStarted = false;
164
165 private static boolean enableReportByWorm = true;
166 private static boolean enableReportByNumattacks = true;
167 private static boolean enableReportByDate = true;
168 private static boolean enableReportByIP = true;
169 private static boolean enableReportByHostname = true;
170
171 private String filename;
172
173 static {
174 //try it just in case JRE 1.4 is installed for charts
175 System.setProperty("java.awt.headless", "true");
176
177 try {
178 pattern = p5.compile( "^(.*?)\\s+(.*?)\\[(.*?)\\](.*?)(GET|POST|HEAD|SEARCH)\\s+(.*?)\\s+(.*?)$" );
179 }
180 catch ( Exception e){
181 System.err.println( "Exception thrown on init: " + e.getMessage() );
182 }
183 }
184
185 /**
186 * Compress a file with GZIP
187 */
188 private static void writeGZIP( String inputFilename, String outputFilename ) throws Exception {
189 BufferedInputStream fis = new BufferedInputStream( new FileInputStream( inputFilename ) );
190 BufferedOutputStream gos = new BufferedOutputStream( new GZIPOutputStream( new FileOutputStream( outputFilename ) ) );
191 byte[] buffer = new byte[GZIP_BUFFER];
192 for(;;){
193 int numBytes = fis.read( buffer, 0, GZIP_BUFFER );
194 if ( numBytes < 0 ) break;
195 gos.write( buffer, 0, numBytes );
196 }
197 fis.close();
198 gos.close();
199 }
200
201 /**
202 * Some static initialization stuff. Read in our DNS cache and create some of our storage Vectors
203 */
204 private static void initialize(){
205 attackStorage = new Vector( INITIAL_ATTACK_STORAGE_SIZE );
206
207 if ( cacheDNS ){
208 try {
209 ObjectInputStream ois = new ObjectInputStream( new FileInputStream(DNS_CACHE_FILENAME) );
210 sourceStorage = (TreeMap)(ois.readObject());
211 ois.close();
212 if ( OUTPUT_LEVEL > 2 ) System.out.println( "DNS Cache loaded" );
213 }
214 catch( Exception e ){
215 sourceStorage = new TreeMap();
216 if ( OUTPUT_LEVEL > 1 ) System.err.println("DNS Cache couldn't be loaded: " + e.getMessage());
217 }
218
219 try {
220 //do some fixup processing of previously-stored objects
221 Iterator i = sourceStorage.values().iterator();
222 while( i.hasNext() ){
223 AttackSource source = (AttackSource)(i.next());
224 source.convertIP();
225 }
226 }
227 catch( Exception e ){
228 if ( OUTPUT_LEVEL > 1 ) System.err.println("Error performing fixup: " + e.getMessage());
229 e.printStackTrace();
230 }
231 }
232 else {
233 sourceStorage = new TreeMap();
234 }
235 }
236
237 /**
238 * IP/Hostname should only be stored once. This method controls that.
239 */
240 private static AttackSource getAttackSource( String ip ){
241 AttackSource as;
242 //changes 3.26.2002 to not synchronize if only one thread
243 //synchronization too expensive if not needed
244 if ( NUM_PARSE_THREADS > 1 ){
245 synchronized( sourceStorage ){
246 as = (AttackSource)(sourceStorage.get(ip));
247 }
248
249 if ( as == null ){
250 as = new AttackSource( ip );
251 synchronized( sourceStorage ){
252 sourceStorage.put( ip, as );
253
254 Resolver.addSource( as );
255 if ( !resolveStarted ){
256 for ( int i = 0; i < NUM_RESOLVER_THREADS; i++ ) {
257 resolverThreads[i] = new Resolver();
258 resolverThreads[i].setPriority(Thread.MIN_PRIORITY);
259 resolverThreads[i].start();
260 }
261 resolveStarted = true;
262 }
263 }
264 }
265 }
266 else {
267 as = (AttackSource)(sourceStorage.get(ip));
268 if ( as == null ){
269 as = new AttackSource( ip );
270 sourceStorage.put( ip, as );
271 Resolver.addSource( as );
272 if ( !resolveStarted ){
273 for ( int i = 0; i < NUM_RESOLVER_THREADS; i++ ) {
274 resolverThreads[i] = new Resolver();
275 resolverThreads[i].setPriority(Thread.MIN_PRIORITY);
276 resolverThreads[i].start();
277 }
278 resolveStarted = true;
279 }
280 }
281 }
282
283 return as;
284 }
285
286 /**
287 * Constructs a parse thread.
288 */
289 public Program( int id, BufferedReader bf, String filename ) {
290 threadID = id;
291 reader = bf;
292 this.filename = filename;
293 matcher = new Perl5Matcher();
294 }
295
296 /**
297 * Begins a parse thread. This will loop until no more lines can be read from file
298 */
299 public void run(){
300 /* read lines until there's nothing left to read */
301 for(;;){
302 try {
303 currentLine = reader.readLine();
304 }
305 catch (Exception e){
306 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: couldn't read a line: " + e.getMessage() );
307 return;
308 }
309 if ( currentLine == null ) return;
310
311 /* check each line against each worm. Do stuff if attack found. */
312 if ( matcher.matches( currentLine, pattern ) ) {
313 MatchResult lineMatch = matcher.getMatch();
314 String uri = lineMatch.group( patternUriIndex );
315 for( int i = 0; i < worms.length; i++ ){
316 if ( matcher.contains( uri, worms[i].getPattern() ) ){
317 String host = lineMatch.group( patternHostIndex );
318 String tempdate = lineMatch.group( patternDateIndex );
319
320 /* try to parse the date */
321 Date date = null;
322 try {
323 if ( patternPrependFilenameToDate ){
324 tempdate = filename + tempdate;
325 }
326 synchronized( patternDateFormat ){
327 date = patternDateFormat.parse( tempdate );
328 }
329 }
330 catch ( Exception e ){
331 if ( OUTPUT_LEVEL > 1 ) System.err.println("cannot interpret date in log file:" + e.getMessage());
332 }
333
334 /* increment attack counter for worm */
335 worms[i].addAttack();
336 AttackSource as = getAttackSource( host );
337
338 /* increment attack counter for host */
339 as.addAttack();
340
341 Attack attack = new Attack( date, worms[i], as );
342 if ( NUM_PARSE_THREADS > 1 ){
343 synchronized( attackStorage ){
344 attackStorage.add( attack );
345 /* check to see if this is the first or last attack by this host.
346 Update if necessary */
347 as.checkAttackDates( attack );
348 }
349 }
350 else {
351 attackStorage.add( attack );
352 as.checkAttackDates( attack );
353 }
354
355 if ( OUTPUT_LEVEL > 3 )
356 System.out.println( "Thread " + threadID + " found " + attack.getAttackingWorm().getShortName() + " attack" );
357
358 /* no need to continue on this line - we've marked it as an attack already */
359 break;
360 }
361 }
362
363 currentLine = null;
364 }
365 /* screw the yield - it's taking up too much of our time to be polite
366 try {
367 this.yield();
368 }
369 catch ( Exception e ){
370 }
371 */
372 }
373 }
374
375 /**
376 * Return a BufferedReader which can read in the log file. Can also detect and handle GZIP/BZIP2 compression
377 */
378 private static BufferedReader getLogfileReader( String filename ) throws Exception{
379 if ( CHECK_GZIP ){
380 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Detecting GZIP... in " + filename );
381 byte[] test = new byte[2];
382 FileInputStream fis = new FileInputStream( filename );
383 int read = fis.read( test, 0, 2 );
384 if ( read == 2 ){
385 if ( test[0] == new Integer( 31 ).byteValue() && test[1] == new Integer( 139 ).byteValue() ){
386 fis.close();
387 fis = new FileInputStream( filename );
388 GZIPInputStream gis = new GZIPInputStream( fis );
389 InputStreamReader isr = new InputStreamReader( gis );
390 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Log file " + filename + " was compressed with GZIP. Decompression will take place automatically." );
391 return new BufferedReader( isr, bufferSize );
392 }
393 }
394 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Log file was NOT compressed with GZIP" );
395 }
396 if ( CHECK_BZIP2 ){
397 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Detecting BZIP2... in " + filename );
398 byte[] test = new byte[4];
399 FileInputStream fis = new FileInputStream( filename );
400 int read = fis.read( test, 0, 2 );
401 if ( read == 2 ){
402 if ( test[0] == 'B' && test[1] == 'Z' ){
403 CBZip2InputStream bis = new CBZip2InputStream( fis );
404 InputStreamReader isr = new InputStreamReader( bis );
405 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Log file " + filename + " was compressed with BZIP2. Decompression will take place automatically." );
406 return new BufferedReader( isr, bufferSize );
407 }
408 }
409 if ( OUTPUT_LEVEL > 2 ) System.out.println( "Log file was NOT compressed with BZIP2" );
410 }
411 FileReader fileInput = new FileReader( filename );
412 return new BufferedReader( fileInput, bufferSize );
413 }
414
415 public static void main(String[] args) {
416 /* the user entered this as our list of logfile(s) to parse */
417 String LOGFILE = null;
418
419 /* this mess reads in the properties file and sets values accordingly */
420 Properties p = new Properties();
421 try {
422 p.load( new FileInputStream("wormscan.properties") );
423 String temp = p.getProperty( "outputLevel" );
424 if ( temp != null ){
425 try {
426 OUTPUT_LEVEL = Integer.parseInt( temp );
427 }
428 catch ( Exception e){
429 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: outputLevel property was not an integer. Using default" );
430 }
431 }
432 else {
433 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: outputLevel property not specified. Using default" );
434 }
435 temp = p.getProperty("reportFilename");
436 if ( temp != null ) BASE_FILENAME = temp;
437 else {
438 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: reportFilename property not specified. Using default" );
439 }
440 temp = p.getProperty("reportExtension");
441 if ( temp != null ) BASE_EXTENSION = temp;
442 else {
443 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: reportExtension property not specified. Using default" );
444 }
445 temp = p.getProperty( "logFile" );
446 if ( temp != null ) LOGFILE = temp;
447 else {
448 if ( OUTPUT_LEVEL > 0 ) System.err.println( "logFile property not specified in wormscan.properties - unable to proceed" );
449 System.exit(1);
450 }
451 temp = p.getProperty( "numAttacksFile" );
452 if ( temp != null ) NUM_ATTACKS_FILE = temp;
453 else {
454 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numAttacksFile property not specified. File won't be written" );
455 }
456 temp = p.getProperty( "initialAttackStorageSize" );
457 if ( temp != null ){
458 try {
459 INITIAL_ATTACK_STORAGE_SIZE = Integer.parseInt( temp );
460 }
461 catch ( Exception e){
462 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: initialAttackStorageSize property was not an integer. Using default" );
463 }
464 }
465 else {
466 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: initialAttackStorageSize property not specified. Using default" );
467 }
468 temp = p.getProperty( "initialSourceStorageSize" );
469 if ( temp != null ){
470 try {
471 INITIAL_SOURCE_STORAGE_SIZE = Integer.parseInt( temp );
472 }
473 catch ( Exception e){
474 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: initialSourceStorageSize property was not an integer. Using default" );
475 }
476 }
477 else {
478 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: initialSourceStorageSize property not specified. Using default" );
479 }
480 temp = p.getProperty( "numParseThreads" );
481 if ( temp != null ){
482 try {
483 NUM_PARSE_THREADS = Integer.parseInt( temp );
484 }
485 catch ( Exception e){
486 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numParseThreads property was not an integer. Using default" );
487 }
488 }
489 else {
490 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numParseThreads property not specified. Using default" );
491 }
492 temp = p.getProperty( "numResolverThreads" );
493 if ( temp != null ){
494 try {
495 NUM_RESOLVER_THREADS = Integer.parseInt( temp );
496 }
497 catch ( Exception e){
498 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numResolverThreads property was not an integer. Using default" );
499 }
500 }
501 else {
502 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numResolverThreads property not specified. Using default" );
503 }
504 temp = p.getProperty( "maxResolverQueue" );
505 if ( temp != null ){
506 try {
507 Resolver.MAX_WAITING = Integer.parseInt( temp );
508 }
509 catch ( Exception e){
510 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: maxResolverQueue property was not an integer. Using default" );
511 }
512 }
513 else {
514 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numResolverThreads property not specified. Using default" );
515 }
516 temp = p.getProperty( "numSortThreads" );
517 if ( temp != null ){
518 try {
519 NUM_RUNNING_SORT_THREADS = Integer.parseInt( temp );
520 }
521 catch ( Exception e){
522 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numSortThreads property was not an integer. Using default" );
523 }
524 }
525 else {
526 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: numSortThreads property not specified. Using default" );
527 }
528 temp = p.getProperty( "cacheDNS" );
529 if ( temp != null ){
530 if ( temp.equals("1") ){
531 cacheDNS = true;
532 temp = p.getProperty( "cacheFilename" );
533 if ( temp != null ){
534 DNS_CACHE_FILENAME = temp;
535 }
536 else if ( OUTPUT_LEVEL > 1 ){
537 System.err.println( "Warning: cacheFilename property not specified. Using default" );
538 }
539 }
540 else if ( temp.equals("0") ){
541 cacheDNS = false;
542 }
543 else if ( OUTPUT_LEVEL > 1 ){
544 System.err.println( "Warning: cacheDNS property is not 1 or 0. Using default" );
545 }
546 }
547 else {
548 if ( OUTPUT_LEVEL > 1 ){
549 System.err.println( "Warning: numResolverThreads property not specified. Using default" );
550 }
551 }
552 temp = p.getProperty( "showLatestAttackOnly" );
553 if ( temp != null ){
554 if ( temp.equals("1") ){
555 SHOW_LATEST_ATTACK_ONLY = true;
556 }
557 else if ( temp.equals("0") ){
558 SHOW_LATEST_ATTACK_ONLY = false;
559 }
560 else if ( OUTPUT_LEVEL > 1 ){
561 System.err.println( "Warning: showLatestAttackOnly property is not 1 or 0. Using default" );
562 }
563 }
564 else {
565 if ( OUTPUT_LEVEL > 1 ){
566 System.err.println( "Warning: showLatestAttackOnly property not specified. Using default" );
567 }
568 }
569 temp = p.getProperty( "resolveDNS" );
570 if ( temp != null ){
571 if ( temp.equals("1") ){
572 RESOLVE_DNS = true;
573 }
574 else if ( temp.equals("0") ){
575 RESOLVE_DNS = false;
576 }
577 else if ( OUTPUT_LEVEL > 1 ){
578 System.err.println( "Warning: resolveDNS property is not 1 or 0. Using default" );
579 }
580 }
581 else {
582 if ( OUTPUT_LEVEL > 1 ){
583 System.err.println( "Warning: resolveDNS property not specified. Using default" );
584 }
585 }
586 temp = p.getProperty( "logCheckGZIP" );
587 if ( temp != null ){
588 if ( temp.equals("1") ){
589 CHECK_GZIP = true;
590 }
591 else if ( temp.equals("0") ){
592 CHECK_GZIP = false;
593 }
594 else if ( OUTPUT_LEVEL > 1 ){
595 System.err.println( "Warning: logCheckGZIP property is not 1 or 0. Using default" );
596 }
597 }
598 else {
599 if ( OUTPUT_LEVEL > 1 ){
600 System.err.println( "Warning: logCheckGZIP property not specified. Using default" );
601 }
602 }
603 temp = p.getProperty( "logCheckBZIP2" );
604 if ( temp != null ){
605 if ( temp.equals("1") ){
606 CHECK_BZIP2 = true;
607 }
608 else if ( temp.equals("0") ){
609 CHECK_BZIP2 = false;
610 }
611 else if ( OUTPUT_LEVEL > 1 ){
612 System.err.println( "Warning: logCheckBZIP2 property is not 1 or 0. Using default" );
613 }
614 }
615 else {
616 if ( OUTPUT_LEVEL > 1 ){
617 System.err.println( "Warning: logCheckBZIP2 property not specified. Using default" );
618 }
619 }
620 temp = p.getProperty( "writeGZIP" );
621 if ( temp != null ){
622 if ( temp.equals("1") ){
623 WRITE_GZIP = true;
624 }
625 else if ( temp.equals("0") ){
626 WRITE_GZIP = false;
627 }
628 else if ( OUTPUT_LEVEL > 1 ){
629 System.err.println( "Warning: writeGZIP property is not 1 or 0. Using default" );
630 }
631 }
632 else {
633 if ( OUTPUT_LEVEL > 1 ){
634 System.err.println( "Warning: writeGZIP property not specified. Using default" );
635 }
636 }
637 temp = p.getProperty( "disableReportByWorm" );
638 if ( temp != null && temp.equals("1") ){
639 enableReportByWorm = false;
640 }
641 temp = p.getProperty( "disableReportByNumattacks" );
642 if ( temp != null && temp.equals("1") ){
643 enableReportByNumattacks = false;
644 }
645 temp = p.getProperty( "disableReportByDate" );
646 if ( temp != null && temp.equals("1") ){
647 enableReportByDate = false;
648 }
649 temp = p.getProperty( "disableReportByIP" );
650 if ( temp != null && temp.equals("1") ){
651 enableReportByIP = false;
652 }
653 temp = p.getProperty( "disableReportByHostname" );
654 if ( temp != null && temp.equals("1") ){
655 enableReportByHostname = false;
656 }
657 temp = p.getProperty( "produceCharts" );
658 if ( temp != null ){
659 if ( temp.equals("1") ) {
660 CHARTS_PRODUCE = true;
661 temp = p.getProperty( "chartFilename" );
662 if ( temp != null && !temp.equals("") ){
663 CHART_BASE_FILENAME = temp;
664 }
665 else if ( OUTPUT_LEVEL > 1 ){
666 System.err.println( "Warning: chartFilename property not specified. Using default" );
667 }
668 temp = p.getProperty( "chartWidth" );
669 if ( temp != null && !temp.equals("") ){
670 try {
671 int tempInt = Integer.parseInt( temp );
672 if ( tempInt >= 50 ){
673 CHART_WIDTH = tempInt;
674 }
675 else if ( OUTPUT_LEVEL > 1 ){
676 System.err.println( "Warning: chartWidth property is too small. Using default" );
677 }
678 }
679 catch ( Exception ex ){
680 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: chartWidth property is not an integer. Using default" );
681 }
682 }
683 else if ( OUTPUT_LEVEL > 1 ){
684 System.err.println( "Warning: chartWidth property not specified. Using default" );
685 }
686 temp = p.getProperty( "chartHeight" );
687 if ( temp != null && !temp.equals("") ){
688 try {
689 int tempInt = Integer.parseInt( temp );
690 if ( tempInt >= 50 ){
691 CHART_HEIGHT = tempInt;
692 }
693 else if ( OUTPUT_LEVEL > 1 ){
694 System.err.println( "Warning: chartHeight property is too small. Using default" );
695 }
696 }
697 catch ( Exception ex ){
698 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: chartHeight property is not an integer. Using default" );
699 }
700 }
701 else if ( OUTPUT_LEVEL > 1 ){
702 System.err.println( "Warning: chartHeight property not specified. Using default" );
703 }
704 }
705 else if ( temp.equals("0") ){
706 CHARTS_PRODUCE = false;
707 }
708 else if ( OUTPUT_LEVEL > 1 ) {
709 System.err.println( "Warning: produceCharts property is not 1 or 0. Using default" );
710 }
711 }
712 else {
713 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: produceCharts property not specified. Charts will not be created" );
714 }
715
716 String locLanguage = "en";
717 String locCountry = "US";
718 temp = p.getProperty( "serverLocaleLanguage" );
719 if ( temp != null && !temp.equals("")){
720 locLanguage = temp;
721 }
722 else {
723 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: serverLocaleLanguage property not specified. Using default" );
724 }
725 temp = p.getProperty( "serverLocaleCountry" );
726 if ( temp != null && !temp.equals("")){
727 locCountry = temp;
728 }
729 else {
730 if ( OUTPUT_LEVEL > 1 ) System.err.println( "Warning: serverLocaleCountry property not specified. Using default" );
731 }
732 if ( !locLanguage.equals("en") || !locCountry.equals("US") ){
733 try {
734 Locale tempLocale = new Locale( locLanguage, locCountry );
735 LOG_LOCALE = tempLocale;
736 patternDateFormat = new SimpleDateFormat(defaultDatePattern, LOG_LOCALE);
737 }
738 catch( Exception e ){
739 System.err.println( "Warning: unable to create Locale for " + locLanguage + ", " + locCountry + ": " + e.getMessage() );
740