home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / cgi-bin / awstats.pl < prev    next >
Encoding:
Perl Script  |  2004-05-20  |  530.5 KB  |  10,245 lines

  1. #!perl/bin/perl
  2. #------------------------------------------------------------------------------
  3. # Free realtime web server logfile analyzer to show advanced web statistics.
  4. # Works from command line or as a CGI. You must use this script as often as
  5. # necessary from your scheduler to update your statistics and from command
  6. # line or a browser to read report results.
  7. # See AWStats documentation (in docs/ directory) for all setup instructions.
  8. #------------------------------------------------------------------------------
  9. # $Revision: 1.3 $ - $Author: joker $ - $Date: 2004/05/20 20:38:42 $
  10. require 5.005;
  11.  
  12. #$|=1;
  13. #use warnings;        # Must be used in test mode only. This reduce a little process speed
  14. #use diagnostics;    # Must be used in test mode only. This reduce a lot of process speed
  15. use strict;no strict "refs";
  16. use Time::Local;    # use Time::Local 'timelocal_nocheck' is faster but not supported by all Time::Local modules
  17. use Socket;
  18.  
  19.  
  20. #------------------------------------------------------------------------------
  21. # Defines
  22. #------------------------------------------------------------------------------
  23. use vars qw/ $REVISION $VERSION /;
  24. $REVISION='$Revision: 1.3 $'; $REVISION =~ /\s(.*)\s/; $REVISION=$1;
  25. $VERSION="6.1 (build $REVISION)";
  26.  
  27. # ----- Constants -----
  28. use vars qw/
  29. $DEBUGFORCED $NBOFLINESFORBENCHMARK $FRAMEWIDTH $NBOFLASTUPDATELOOKUPTOSAVE
  30. $LIMITFLUSH $NEWDAYVISITTIMEOUT $VISITTIMEOUT $NOTSORTEDRECORDTOLERANCE
  31. $WIDTHCOLICON $TOOLTIPON
  32. $lastyearbeforeupdate
  33. /;
  34. $DEBUGFORCED=0;                        # Force debug level to log lesser level into debug.log file (Keep this value to 0)
  35. $NBOFLINESFORBENCHMARK=8192;        # Benchmark info are printing every NBOFLINESFORBENCHMARK lines (Must be a power of 2)
  36. $FRAMEWIDTH=240;                    # Width of left frame when UseFramesWhenCGI is on
  37. $NBOFLASTUPDATELOOKUPTOSAVE=500;    # Nb of records to save in DNS last update cache file
  38. $LIMITFLUSH=5000;                    # Nb of records in data arrays after how we need to flush data on disk
  39. $NEWDAYVISITTIMEOUT=764041;            # Delay between 01-23:59:59 and 02-00:00:00
  40. $VISITTIMEOUT=10000;                # Lapse of time to consider a page load as a new visit. 10000 = 1 hour (Default = 10000)
  41. $NOTSORTEDRECORDTOLERANCE=10000;    # Lapse of time to accept a record if not in correct order. 10000 = 1 hour (Default = 10000)
  42. $WIDTHCOLICON=32;
  43. $TOOLTIPON=0;                        # Tooltips plugin loaded
  44. # ----- Running variables -----
  45. use vars qw/
  46. $DIR $PROG $Extension
  47. $Debug $ShowSteps
  48. $DebugResetDone $DNSLookupAlreadyDone
  49. $RunAsCli $UpdateFor $HeaderHTTPSent $HeaderHTMLSent
  50. $LastLine $LastLineNumber $LastLineOffset $LastLineChecksum $LastUpdate
  51. $lowerval
  52. $PluginMode
  53. $TotalUnique $TotalVisits $TotalHostsKnown $TotalHostsUnknown
  54. $TotalPages $TotalHits $TotalBytes
  55. $TotalNotViewedPages $TotalNotViewedHits $TotalNotViewedBytes
  56. $TotalEntries $TotalExits $TotalBytesPages $TotalDifferentPages
  57. $TotalKeyphrases $TotalKeywords $TotalDifferentKeyphrases $TotalDifferentKeywords
  58. $TotalSearchEnginesPages $TotalSearchEnginesHits $TotalRefererPages $TotalRefererHits $TotalDifferentSearchEngines $TotalDifferentReferer
  59. $FrameName $Center $FileConfig $FileSuffix $Host $DayRequired $MonthRequired $YearRequired
  60. $QueryString $SiteConfig $StaticLinks $PageCode $PageDir $PerlParsingFormat $UserAgent
  61. $pos_vh $pos_host $pos_logname $pos_date $pos_tz $pos_method $pos_url $pos_code $pos_size
  62. $pos_referer $pos_agent $pos_query $pos_gzipin $pos_gzipout $pos_compratio
  63. $pos_cluster $pos_emails $pos_emailr $pos_hostr
  64. /;
  65. $DIR=$PROG=$Extension='';
  66. $Debug = $ShowSteps = 0;
  67. $DebugResetDone = $DNSLookupAlreadyDone = 0;
  68. $RunAsCli = $UpdateFor = $HeaderHTTPSent = $HeaderHTMLSent = 0;
  69. $LastLine = $LastLineNumber = $LastLineOffset = $LastLineChecksum = $LastUpdate = 0;
  70. $lowerval = 0;
  71. $PluginMode = '';
  72. $TotalUnique = $TotalVisits = $TotalHostsKnown = $TotalHostsUnknown = 0;
  73. $TotalPages = $TotalHits = $TotalBytes = 0;
  74. $TotalNotViewedPages = $TotalNotViewedHits = $TotalNotViewedBytes = 0;
  75. $TotalEntries = $TotalExits = $TotalBytesPages = $TotalDifferentPages = 0;
  76. $TotalKeyphrases = $TotalKeywords = $TotalDifferentKeyphrases = $TotalDifferentKeywords = 0;
  77. $TotalSearchEnginesPages = $TotalSearchEnginesHits = $TotalRefererPages = $TotalRefererHits = $TotalDifferentSearchEngines = $TotalDifferentReferer = 0;
  78. ($FrameName, $Center, $FileConfig, $FileSuffix, $Host, $DayRequired, $MonthRequired, $YearRequired,
  79. $QueryString, $SiteConfig, $StaticLinks, $PageCode, $PageDir, $PerlParsingFormat, $UserAgent)=
  80. ('','','','','','','','','','','','','','','');
  81. $pos_vh = $pos_host = $pos_logname = $pos_date = $pos_tz = $pos_method = $pos_url = $pos_code = $pos_size = -1;
  82. $pos_referer = $pos_agent = $pos_query = $pos_gzipin = $pos_gzipout = $pos_compratio = -1;
  83. $pos_cluster = $pos_emails = $pos_emailr = $pos_hostr = -1;
  84. # ----- Plugins variable -----
  85. use vars qw/ %PluginsLoaded $PluginDir /;
  86. %PluginsLoaded=();
  87. $PluginDir='';
  88. # ----- Time vars -----
  89. use vars qw/
  90. $starttime
  91. $nowtime $tomorrowtime
  92. $nowweekofmonth $nowweekofyear $nowdaymod $nowsmallyear
  93. $nowsec $nowmin $nowhour $nowday $nowmonth $nowyear $nowwday $nowyday $nowns
  94. $StartSeconds $StartMicroseconds
  95. /;
  96. $StartSeconds=$StartMicroseconds=0;
  97. # ----- Variables for config file reading -----
  98. use vars qw/
  99. $FoundNotPageList
  100. /;
  101. $FoundNotPageList=0;
  102. # ----- Config file variables -----
  103. use vars qw/
  104. $StaticExt
  105. $DNSStaticCacheFile
  106. $DNSLastUpdateCacheFile
  107. $MiscTrackerUrl
  108. $Lang
  109. $MaxRowsInHTMLOutput
  110. $MaxLengthOfShownURL
  111. $MaxLengthOfStoredURL
  112. $MaxLengthOfStoredUA
  113. %BarPng
  114. $BuildReportFormat
  115. $BuildHistoryFormat
  116. $ExtraTrackedRowsLimit
  117. /;
  118. $StaticExt='html';
  119. $DNSStaticCacheFile='dnscache.txt';
  120. $DNSLastUpdateCacheFile='dnscachelastupdate.txt';
  121. $MiscTrackerUrl='/js/awstats_misc_tracker.js';
  122. $Lang='auto';
  123. $MaxRowsInHTMLOutput=1000;
  124. $MaxLengthOfShownURL=64;
  125. $MaxLengthOfStoredURL=256;            # Note: Apache LimitRequestLine is default to 8190
  126. $MaxLengthOfStoredUA=256;
  127. %BarPng=('vv'=>'vv.png','vu'=>'vu.png','hu'=>'hu.png','vp'=>'vp.png','hp'=>'hp.png',
  128. 'he'=>'he.png','hx'=>'hx.png','vh'=>'vh.png','hh'=>'hh.png','vk'=>'vk.png','hk'=>'hk.png');
  129. $BuildReportFormat='html';
  130. $BuildHistoryFormat='text';
  131. $ExtraTrackedRowsLimit=500;
  132. use vars qw/
  133. $EnableLockForUpdate $DNSLookup $AllowAccessFromWebToAuthenticatedUsersOnly
  134. $BarHeight $BarWidth $CreateDirDataIfNotExists $KeepBackupOfHistoricFiles
  135. $NbOfLinesParsed $NbOfLinesDropped $NbOfLinesCorrupted $NbOfOldLines $NbOfNewLines
  136. $NbOfLinesShowsteps $NewLinePhase $NbOfLinesForCorruptedLog $PurgeLogFile $ArchiveLogRecords
  137. $ShowDropped $ShowCorrupted $ShowUnknownOrigin $ShowLinksToWhoIs
  138. $ShowAuthenticatedUsers $ShowFileSizesStats $ShowScreenSizeStats $ShowSMTPErrorsStats
  139. $ShowEMailSenders $ShowEMailReceivers $ShowWormsStats $ShowClusterStats
  140. $IncludeInternalLinksInOriginSection
  141. $AuthenticatedUsersNotCaseSensitive
  142. $Expires $UpdateStats $MigrateStats $URLNotCaseSensitive $URLWithQuery $URLReferrerWithQuery
  143. $DecodeUA
  144. /;
  145. ($EnableLockForUpdate, $DNSLookup, $AllowAccessFromWebToAuthenticatedUsersOnly,
  146. $BarHeight, $BarWidth, $CreateDirDataIfNotExists, $KeepBackupOfHistoricFiles,
  147. $NbOfLinesParsed, $NbOfLinesDropped, $NbOfLinesCorrupted, $NbOfOldLines, $NbOfNewLines,
  148. $NbOfLinesShowsteps, $NewLinePhase, $NbOfLinesForCorruptedLog, $PurgeLogFile, $ArchiveLogRecords,
  149. $ShowDropped, $ShowCorrupted, $ShowUnknownOrigin, $ShowLinksToWhoIs,
  150. $ShowAuthenticatedUsers, $ShowFileSizesStats, $ShowScreenSizeStats, $ShowSMTPErrorsStats,
  151. $ShowEMailSenders, $ShowEMailReceivers, $ShowWormsStats, $ShowClusterStats,
  152. $IncludeInternalLinksInOriginSection,
  153. $AuthenticatedUsersNotCaseSensitive,
  154. $Expires, $UpdateStats, $MigrateStats, $URLNotCaseSensitive, $URLWithQuery, $URLReferrerWithQuery,
  155. $DecodeUA)=
  156. (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
  157. use vars qw/
  158. $AllowToUpdateStatsFromBrowser $DetailedReportsOnNewWindows
  159. $FirstDayOfWeek $KeyWordsNotSensitive $SaveDatabaseFilesWithPermissionsForEveryone
  160. $WarningMessages $DebugMessages $ShowLinksOnUrl $UseFramesWhenCGI
  161. $ShowMenu $ShowMonthStats $ShowDaysOfMonthStats $ShowDaysOfWeekStats
  162. $ShowHoursStats $ShowDomainsStats $ShowHostsStats
  163. $ShowRobotsStats $ShowSessionsStats $ShowPagesStats $ShowFileTypesStats
  164. $ShowOSStats $ShowBrowsersStats $ShowOriginStats
  165. $ShowKeyphrasesStats $ShowKeywordsStats $ShowMiscStats $ShowHTTPErrorsStats
  166. $AddDataArrayMonthStats $AddDataArrayShowDaysOfMonthStats $AddDataArrayShowDaysOfWeekStats $AddDataArrayShowHoursStats
  167. /;
  168. ($AllowToUpdateStatsFromBrowser, $DetailedReportsOnNewWindows,
  169. $FirstDayOfWeek, $KeyWordsNotSensitive, $SaveDatabaseFilesWithPermissionsForEveryone,
  170. $WarningMessages, $DebugMessages, $ShowLinksOnUrl, $UseFramesWhenCGI,
  171. $ShowMenu, $ShowMonthStats, $ShowDaysOfMonthStats, $ShowDaysOfWeekStats,
  172. $ShowHoursStats, $ShowDomainsStats, $ShowHostsStats,
  173. $ShowRobotsStats, $ShowSessionsStats, $ShowPagesStats, $ShowFileTypesStats,
  174. $ShowOSStats, $ShowBrowsersStats, $ShowOriginStats,
  175. $ShowKeyphrasesStats, $ShowKeywordsStats, $ShowMiscStats, $ShowHTTPErrorsStats,
  176. $AddDataArrayMonthStats, $AddDataArrayShowDaysOfMonthStats, $AddDataArrayShowDaysOfWeekStats, $AddDataArrayShowHoursStats
  177. )=
  178. (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1);
  179. use vars qw/
  180. $AllowFullYearView 
  181. $LevelForRobotsDetection $LevelForWormsDetection $LevelForBrowsersDetection $LevelForOSDetection $LevelForRefererAnalyze
  182. $LevelForFileTypesDetection $LevelForSearchEnginesDetection $LevelForKeywordsDetection
  183. /;
  184. ($AllowFullYearView,
  185. $LevelForRobotsDetection, $LevelForWormsDetection, $LevelForBrowsersDetection, $LevelForOSDetection, $LevelForRefererAnalyze,
  186. $LevelForFileTypesDetection, $LevelForSearchEnginesDetection, $LevelForKeywordsDetection)=
  187. (2,2,0,2,2,2,2,2,2);
  188. use vars qw/
  189. $DirLock $DirCgi $DirConfig $DirData $DirIcons $DirLang $AWScript $ArchiveFileName
  190. $AllowAccessFromWebToFollowingIPAddresses $HTMLHeadSection $HTMLEndSection $LinksToWhoIs $LinksToIPWhoIs
  191. $LogFile $LogType $LogFormat $LogSeparator $Logo $LogoLink $StyleSheet $WrapperScript $SiteDomain
  192. $UseHTTPSLinkForUrl $URLQuerySeparators $URLWithAnchor $ErrorMessages $ShowFlagLinks
  193. /;
  194. ($DirLock, $DirCgi, $DirConfig, $DirData, $DirIcons, $DirLang, $AWScript, $ArchiveFileName,
  195. $AllowAccessFromWebToFollowingIPAddresses, $HTMLHeadSection, $HTMLEndSection, $LinksToWhoIs, $LinksToIPWhoIs,
  196. $LogFile, $LogType, $LogFormat, $LogSeparator, $Logo, $LogoLink, $StyleSheet, $WrapperScript, $SiteDomain,
  197. $UseHTTPSLinkForUrl, $URLQuerySeparators, $URLWithAnchor, $ErrorMessages, $ShowFlagLinks)=
  198. ('','','','','','','','','','','','','','','','','','','','','','','','','','','');
  199. use vars qw/
  200. $color_Background $color_TableBG $color_TableBGRowTitle
  201. $color_TableBGTitle $color_TableBorder $color_TableRowTitle $color_TableTitle
  202. $color_text $color_textpercent $color_titletext $color_weekend $color_link $color_hover $color_other
  203. $color_h $color_k $color_p $color_e $color_x $color_s $color_u $color_v
  204. /;
  205. ($color_Background, $color_TableBG, $color_TableBGRowTitle,
  206. $color_TableBGTitle, $color_TableBorder, $color_TableRowTitle, $color_TableTitle,
  207. $color_text, $color_textpercent, $color_titletext, $color_weekend, $color_link, $color_hover, $color_other,
  208. $color_h, $color_k, $color_p, $color_e, $color_x, $color_s, $color_u, $color_v)=
  209. ('','','','','','','','','','','','','','','','','','','','','','');
  210. # ---------- Init arrays --------
  211. use vars qw/
  212. @RobotsSearchIDOrder_list1 @RobotsSearchIDOrder_list2 @RobotsSearchIDOrder_listgen
  213. @SearchEnginesSearchIDOrder_list1 @SearchEnginesSearchIDOrder_list2 @SearchEnginesSearchIDOrder_listgen
  214. @BrowsersSearchIDOrder @OSSearchIDOrder @WordsToExtractSearchUrl @WordsToCleanSearchUrl
  215. @WormsSearchIDOrder
  216. @RobotsSearchIDOrder @SearchEnginesSearchIDOrder
  217. @_from_p @_from_h
  218. @_time_p @_time_h @_time_k @_time_nv_p @_time_nv_h @_time_nv_k
  219. @DOWIndex @fieldlib @keylist
  220. /;
  221. @RobotsSearchIDOrder = @SearchEnginesSearchIDOrder = ();
  222. @_from_p = @_from_h = ();
  223. @_time_p = @_time_h = @_time_k = @_time_nv_p = @_time_nv_h = @_time_nv_k = ();
  224. @DOWIndex = @fieldlib = @keylist = ();
  225. use vars qw/
  226. @MiscListOrder %MiscListCalc
  227. @OSFamily %BrowsersFamily @SessionsRange %SessionsAverage
  228. %LangBrowserToLangAwstats %LangAWStatsToCountryAwstats
  229. @HostAliases @AllowAccessFromWebToFollowingAuthenticatedUsers
  230. @DefaultFile @SkipDNSLookupFor
  231. @SkipHosts @SkipUserAgents @SkipFiles
  232. @OnlyHosts @OnlyUserAgents @OnlyFiles 
  233. @URLWithQueryWithOnly @URLWithQueryWithout
  234. @ExtraName @ExtraCondition @ExtraStatTypes @MaxNbOfExtra @MinHitExtra
  235. @ExtraFirstColumnTitle @ExtraFirstColumnValues @ExtraFirstColumnFormat
  236. @ExtraCodeFilter @ExtraConditionType @ExtraConditionTypeVal
  237. @ExtraFirstColumnValuesType @ExtraFirstColumnValuesTypeVal
  238. @ExtraAddAverageRow @ExtraAddSumRow
  239. @PluginsToLoad 
  240. /;
  241. @MiscListOrder=('AddToFavourites','JavaEnabled','DirectorSupport','FlashSupport','RealPlayerSupport','QuickTimeSupport','WindowsMediaPlayerSupport','PDFSupport');
  242. %MiscListCalc=('TotalMisc'=>'','AddToFavourites'=>'u','JavaEnabled'=>'hm','DirectorSupport'=>'hm','FlashSupport'=>'hm','RealPlayerSupport'=>'hm','QuickTimeSupport'=>'hm','WindowsMediaPlayerSupport'=>'hm','PDFSupport'=>'hm');
  243. @OSFamily=('win','mac');
  244. #%BrowsersFamily=('msie'=>1,'netscape'=>2,'mozilla'=>3);
  245. %BrowsersFamily=('msie'=>1,'netscape'=>2);
  246. @SessionsRange=('0s-30s','30s-2mn','2mn-5mn','5mn-15mn','15mn-30mn','30mn-1h','1h+');
  247. %SessionsAverage=('0s-30s',15,'30s-2mn',75,'2mn-5mn',210,'5mn-15mn',600,'15mn-30mn',1350,'30mn-1h',2700,'1h+',3600);
  248. # Values reported by HTTP-Accept with AWStats code to use
  249. %LangBrowserToLangAwstats=('sq'=>'al','ba'=>'ba','bg'=>'bg','zh-tw'=>'tw','zh'=>'cn','cz'=>'cz',
  250. 'da'=>'dk','nl'=>'nl','en'=>'en','et'=>'et','fi'=>'fi','fr'=>'fr',
  251. 'de'=>'de','el'=>'gr','hu'=>'hu','is'=>'is','in'=>'id','it'=>'it',
  252. 'ja'=>'jp','ko'=>'kr','lv'=>'lv','no'=>'nb','nb'=>'nb','nn'=>'nn','pl'=>'pl','pt'=>'pt','pt-br'=>'br',
  253. 'ro'=>'ro','ru'=>'ru','sr'=>'sr','sk'=>'sk','es'=>'es','eu'=>'es_eu','ca'=>'es_cat','sv'=>'se','tr'=>'tr','uk'=>'ua','wlk'=>'wlk');
  254. %LangAWStatsToCountryAwstats=('et'=>'ee','he'=>'il');
  255. @HostAliases = @AllowAccessFromWebToFollowingAuthenticatedUsers=();
  256. @DefaultFile = @SkipDNSLookupFor = ();
  257. @SkipHosts = @SkipUserAgents = @SkipFiles = ();
  258. @OnlyHosts = @OnlyUserAgents = @OnlyFiles = ();
  259. @URLWithQueryWithOnly = @URLWithQueryWithout = ();
  260. @ExtraName = @ExtraCondition = @ExtraStatTypes = @MaxNbOfExtra = @MinHitExtra = ();
  261. @ExtraFirstColumnTitle = @ExtraFirstColumnValues = @ExtraFirstColumnFormat = ();
  262. @ExtraCodeFilter = @ExtraConditionType = @ExtraConditionTypeVal = ();
  263. @ExtraFirstColumnValuesType = @ExtraFirstColumnValuesTypeVal = ();
  264. @ExtraAddAverageRow = @ExtraAddSumRow = ();
  265. @PluginsToLoad = ();
  266. # ---------- Init hash arrays --------
  267. use vars qw/
  268. %BrowsersHashIDLib %BrowsersHashIcon %BrowsersHereAreGrabbers 
  269. %DomainsHashIDLib
  270. %MimeHashLib %MimeHashIcon %MimeHashFamily
  271. %OSHashID %OSHashLib
  272. %RobotsHashIDLib %RobotsAffiliateLib
  273. %SearchEnginesHashID %SearchEnginesHashLib %SearchEnginesKnownUrl %NotSearchEnginesKeys
  274. %WormsHashID %WormsHashLib %WormsHashTarget
  275. /;
  276. use vars qw/
  277. %HTMLOutput %NoLoadPlugin %FilterIn %FilterEx
  278. %BadFormatWarning
  279. %MonthNumLib
  280. %ValidHTTPCodes %ValidSMTPCodes
  281. %TrapInfosForHTTPErrorCodes %NotPageList %DayBytes %DayHits %DayPages %DayVisits
  282. %MaxNbOf %MinHit
  283. %ListOfYears %HistoryAlreadyFlushed %PosInFile %ValueInFile
  284. %val %nextval %egal
  285. %TmpDNSLookup %TmpOS %TmpRefererServer %TmpRobot %TmpBrowser %MyDNSTable
  286. /;
  287. %HTMLOutput = %NoLoadPlugin = %FilterIn = %FilterEx = ();
  288. %BadFormatWarning = ();
  289. %MonthNumLib = ();
  290. %ValidHTTPCodes = %ValidSMTPCodes = ();
  291. %TrapInfosForHTTPErrorCodes=(); $TrapInfosForHTTPErrorCodes{404}=1;    # TODO Add this in config file
  292. %NotPageList=();
  293. %DayBytes = %DayHits = %DayPages = %DayVisits = ();
  294. %MaxNbOf = %MinHit = ();
  295. %ListOfYears = %HistoryAlreadyFlushed = %PosInFile = %ValueInFile = ();
  296. %val = %nextval = %egal = ();
  297. %TmpDNSLookup = %TmpOS = %TmpRefererServer = %TmpRobot = %TmpBrowser = %MyDNSTable = ();
  298. use vars qw/
  299. %FirstTime %LastTime
  300. %MonthHostsKnown %MonthHostsUnknown
  301. %MonthUnique %MonthVisits
  302. %MonthPages %MonthHits %MonthBytes
  303. %MonthNotViewedPages %MonthNotViewedHits %MonthNotViewedBytes
  304. %_session %_browser_h
  305. %_domener_p %_domener_h %_domener_k %_errors_h %_errors_k
  306. %_filetypes_h %_filetypes_k %_filetypes_gz_in %_filetypes_gz_out
  307. %_host_p %_host_h %_host_k %_host_l %_host_s %_host_u
  308. %_waithost_e %_waithost_l %_waithost_s %_waithost_u
  309. %_keyphrases %_keywords %_os_h %_pagesrefs_p %_pagesrefs_h %_robot_h %_robot_k %_robot_l %_robot_r
  310. %_worm_h %_worm_k %_worm_l %_login_h %_login_p %_login_k %_login_l %_screensize_h
  311. %_misc_p %_misc_h %_misc_k
  312. %_cluster_p %_cluster_h %_cluster_k
  313. %_se_referrals_p %_se_referrals_h %_sider404_h %_referer404_h %_url_p %_url_k %_url_e %_url_x
  314. %_unknownreferer_l %_unknownrefererbrowser_l
  315. %_emails_h %_emails_k %_emails_l %_emailr_h %_emailr_k %_emailr_l
  316. /;
  317. &Init_HashArray();
  318. # ---------- Init Regex --------
  319. use vars qw/ $regclean1 $regclean2 /;
  320. $regclean1=qr/<(recnb|\/td)>/i;
  321. $regclean2=qr/<\/?[^<>]+>/i;
  322.  
  323. # ---------- Init Tie::hash arrays --------
  324. # Didn't find a tie that increase speed
  325. #use Tie::StdHash;
  326. #use Tie::Cache::LRU;
  327. #tie %_host_p, 'Tie::StdHash';
  328. #tie %TmpOS, 'Tie::Cache::LRU';
  329.  
  330. # PROTOCOL CODES
  331. use vars qw/ %httpcodelib %ftpcodelib %smtpcodelib /;
  332.  
  333. # DEFAULT MESSAGE
  334. use vars qw/ @Message /;
  335. @Message=(
  336. 'Unknown',
  337. 'Unknown (unresolved ip)',
  338. 'Others',
  339. 'View details',
  340. 'Day',
  341. 'Month',
  342. 'Year',
  343. 'Statistics for',
  344. 'First visit',
  345. 'Last visit',
  346. 'Number of visits',
  347. 'Unique visitors',
  348. 'Visit',
  349. 'different keywords',
  350. 'Search',
  351. 'Percent',
  352. 'Traffic',
  353. 'Domains/Countries',
  354. 'Visitors',
  355. 'Pages-URL',
  356. 'Hours',
  357. 'Browsers',
  358. '',
  359. 'Referers',
  360. 'Never updated (See \'Build/Update\' on awstats_setup.html page)',
  361. 'Visitors domains/countries',
  362. 'hosts',
  363. 'pages',
  364. 'different pages-url',
  365. 'Viewed',
  366. 'Other words',
  367. 'Pages not found',
  368. 'HTTP Error codes',
  369. 'Netscape versions',
  370. 'IE versions',
  371. 'Last Update',
  372. 'Connect to site from',
  373. 'Origin',
  374. 'Direct address / Bookmarks',
  375. 'Origin unknown',
  376. 'Links from an Internet Search Engine',
  377. 'Links from an external page (other web sites except search engines)',
  378. 'Links from an internal page (other page on same site)',
  379. 'Keyphrases used on search engines',
  380. 'Keywords used on search engines',
  381. 'Unresolved IP Address',
  382. 'Unknown OS (Referer field)',
  383. 'Required but not found URLs (HTTP code 404)',
  384. 'IP Address',
  385. 'Error Hits',
  386. 'Unknown browsers (Referer field)',
  387. 'different robots',
  388. 'visits/visitor',
  389. 'Robots/Spiders visitors',
  390. 'Free realtime logfile analyzer for advanced web statistics',
  391. 'of',
  392. 'Pages',
  393. 'Hits',
  394. 'Versions',
  395. 'Operating Systems',
  396. 'Jan',
  397. 'Feb',
  398. 'Mar',
  399. 'Apr',
  400. 'May',
  401. 'Jun',
  402. 'Jul',
  403. 'Aug',
  404. 'Sep',
  405. 'Oct',
  406. 'Nov',
  407. 'Dec',
  408. 'Navigation',
  409. 'File type',
  410. 'Update now',
  411. 'Bandwidth',
  412. 'Back to main page',
  413. 'Top',
  414. 'dd mmm yyyy - HH:MM',
  415. 'Filter',
  416. 'Full list',
  417. 'Hosts',
  418. 'Known',
  419. 'Robots',
  420. 'Sun',
  421. 'Mon',
  422. 'Tue',
  423. 'Wed',
  424. 'Thu',
  425. 'Fri',
  426. 'Sat',
  427. 'Days of week',
  428. 'Who',
  429. 'When',
  430. 'Authenticated users',
  431. 'Min',
  432. 'Average',
  433. 'Max',
  434. 'Web compression',
  435. 'Bandwidth saved',
  436. 'Compression on',
  437. 'Compression result',
  438. 'Total',
  439. 'different keyphrases',
  440. 'Entry',
  441. 'Code',
  442. 'Average size',
  443. 'Links from a NewsGroup',
  444. 'KB',
  445. 'MB',
  446. 'GB',
  447. 'Grabber',
  448. 'Yes',
  449. 'No',
  450. 'Info.',
  451. 'OK',
  452. 'Exit',
  453. 'Visits duration',
  454. 'Close window',
  455. 'Bytes',
  456. 'Search Keyphrases',
  457. 'Search Keywords',
  458. 'different refering search engines',
  459. 'different refering sites',
  460. 'Other phrases',
  461. 'Other logins (and/or anonymous users)',
  462. 'Refering search engines',
  463. 'Refering sites',
  464. 'Summary',
  465. 'Exact value not available in "Year" view',
  466. 'Data value arrays',
  467. 'Sender EMail',
  468. 'Receiver EMail',
  469. 'Reported period',
  470. 'Extra/Marketing',
  471. 'Screen sizes',
  472. 'Worm/Virus attacks',
  473. 'Add to favorites (estimated)',
  474. 'Days of month',
  475. 'Miscellaneous',
  476. 'Browsers with Java support',
  477. 'Browsers with Macromedia Director Support',
  478. 'Browsers with Flash Support',
  479. 'Browsers with Real audio playing support',
  480. 'Browsers with Quictime audio playing support',
  481. 'Browsers with Windows Media audio playing support',
  482. 'Browsers with PDF support',
  483. 'SMTP Error codes',
  484. 'Countries',
  485. 'Mails',
  486. 'Size',
  487. 'First',
  488. 'Last',
  489. 'Exclude filter',
  490. 'Codes shown here gave hits or traffic "not viewed" by visitors, so they are not included in other charts.',
  491. 'Cluster',
  492. 'Robots shown here gave hits or traffic "not viewed" by visitors, so they are not included in other charts.',
  493. 'Numbers after + are successful hits on "robots.txt" files',
  494. 'Worms shown here gave hits or traffic "not viewed" by visitors, so thay are not included in other charts.',
  495. 'Not viewed traffic includes traffic generated by robots, worms, or replies with special HTTP status codes.',
  496. 'Traffic viewed',
  497. 'Traffic not viewed',
  498. 'Monthly history',
  499. 'Worms',
  500. 'different worms',
  501. 'Mails successfully sent',
  502. 'Mails failed/refused',
  503. 'Sensitive targets'
  504. );
  505.  
  506.  
  507.  
  508. #------------------------------------------------------------------------------
  509. # Functions
  510. #------------------------------------------------------------------------------
  511.  
  512. #------------------------------------------------------------------------------
  513. # Function:        Write on ouput header of HTTP answer
  514. # Parameters:    None
  515. # Input:        $HeaderHTTPSent $BuildReportFormat $PageCode $Expires
  516. # Output:        $HeaderHTTPSent=1
  517. # Return:        None
  518. #------------------------------------------------------------------------------
  519. sub http_head {
  520.     if (! $HeaderHTTPSent) {
  521.         if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { print ($ENV{'HTTP_USER_AGENT'}=~/MSIE|Googlebot/i?"Content-type: text/html; charset=$PageCode\n":"Content-type: text/xml; charset=$PageCode\n"); }
  522.         else { print "Content-type: text/html; charset=$PageCode\n"; }
  523.  
  524.         # Expires must be GMT ANSI asctime and must be after Content-type to avoid pb with some servers (SAMBAR)
  525.         if ($Expires =~ /^\d+$/) {
  526.             print "Cache-Control: public\n";
  527.             print "Last-Modified: ".gmtime($starttime)."\n";
  528.             print "Expires: ".(gmtime($starttime+$Expires))."\n";
  529.         }
  530.         print "\n";
  531.     }
  532.     $HeaderHTTPSent++;;
  533. }
  534.  
  535. #------------------------------------------------------------------------------
  536. # Function:        Write on ouput header of HTML page
  537. # Parameters:    None
  538. # Input:        %HTMLOutput $PluginMode $Expires $Lang $StyleSheet $HTMLHeadSection $PageCode $PageDir
  539. # Output:        $HeaderHTMLSent=1
  540. # Return:        None
  541. #------------------------------------------------------------------------------
  542. sub html_head {
  543.     my $dir=$PageDir?'right':'left';
  544.     if (scalar keys %HTMLOutput || $PluginMode) {
  545.         my $MetaRobot=0;    # meta robots
  546.         # Write head section
  547.         if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') {
  548.             if ($PageCode) { print "<?xml version=\"1.0\" encoding=\"$PageCode\"?>\n"; }
  549.             else { print "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"; };
  550.             if ($FrameName ne 'index') { print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";  }
  551.             else { print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">\n"; }
  552.             print "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"$Lang\">\n";
  553.         } else {
  554.             if ($FrameName ne 'index') { print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n\n";  }
  555.             else { print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\">\n\n"; }
  556.             print "<html lang='$Lang'".($PageDir?" dir='rtl'":"").">\n";
  557.         }
  558.         print "<head>\n";
  559.  
  560.         print "<meta name=\"generator\" content=\"AWStats $VERSION from config file awstats.$SiteConfig.conf (http://awstats.sourceforge.net)\" />\n";
  561.  
  562.         if ($MetaRobot) { print "<meta name=\"robots\" content=\"".($FrameName eq 'mainleft'?'no':'')."index,nofollow\" />\n"; }
  563.         else { print "<meta name=\"robots\" content=\"noindex,nofollow\" />\n"; }
  564.  
  565.         # Affiche tag meta content-type
  566.         if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { print ($ENV{'HTTP_USER_AGENT'}=~/MSIE|Googlebot/i?"<meta http-equiv=\"content-type\" content=\"text/html; charset=".($PageCode?$PageCode:"iso-8859-1")."\" />\n":"<meta http-equiv=\"content-type\" content=\"text/xml; charset=".($PageCode?$PageCode:"iso-8859-1")."\" />\n"); }
  567.         else { print "<meta http-equiv=\"content-type\" content=\"text/html; charset=".($PageCode?$PageCode:"iso-8859-1")."\" />\n"; }
  568.  
  569.         if ($Expires)  { print "<meta http-equiv=\"expires\" content=\"".(gmtime($starttime+$Expires))."\" />\n"; }
  570.         print "<meta http-equiv=\"description\" content=\"".ucfirst($PROG)." - Advanced Web Statistics for $SiteDomain\" />\n";
  571.         if ($MetaRobot && $FrameName ne 'mainleft') { print "<meta http-equiv=\"keywords\" content=\"$SiteDomain, free, advanced, realtime, web, server, logfile, log, analyzer, analysis, statistics, stats, perl, analyse, performance, hits, visits\" />\n"; }
  572.         print "<title>$Message[7] $SiteDomain</title>\n";
  573.         if ($FrameName ne 'index') {
  574.  
  575.             # A STYLE section must be in head section. Do not use " for number in a style section
  576.             print "<style type=\"text/css\">\n";
  577.             if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { print ($ENV{'HTTP_USER_AGENT'}=~/Firebird/i?"<!--\n":"<![CDATA[\n"); }
  578.             else { print "<!--\n"; }
  579. print "body { font: 11px verdana, arial, helvetica, sans-serif; background-color: #$color_Background; margin-top: 0; margin-bottom: 0; }\n";
  580. print ".aws_bodyl  { }\n";
  581. print ".aws_border { background-color: #$color_TableBG; padding: 1px 1px ".($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml'?"2px":"1px")." 1px; margin-top: 0; margin-bottom: 0; }\n";
  582. print ".aws_title  { font: 13px verdana, arial, helvetica, sans-serif; font-weight: bold; background-color: #$color_TableBGTitle; text-align: center; margin-top: 0; margin-bottom: 0; padding: 1px 1px 1px 1px; color: #$color_TableTitle; }\n";
  583. print ".aws_blank  { font: 13px verdana, arial, helvetica, sans-serif; background-color: #".($ENV{'HTTP_USER_AGENT'} && $ENV{'HTTP_USER_AGENT'}=~/MSIE/i?$color_Background:$color_TableBG)."; text-align: center; margin-bottom: 0; padding: 1px 1px 1px 1px; }\n";
  584. print <<EOF;
  585. .aws_data {
  586.     background-color: #$color_Background;
  587.     border-top-width: 1px;   
  588.     border-left-width: 0px;  
  589.     border-right-width: 0px; 
  590.     border-bottom-width: 0px;
  591. }
  592. .aws_formfield { font: 13px verdana, arial, helvetica; }
  593. .aws_button {
  594.     font-family: arial,verdana,helvetica, sans-serif;
  595.     font-size: 12px;
  596.     border: 1px solid #ccd7e0;
  597.     background-image : url($DirIcons/other/button.gif);
  598. }
  599. th        { border-color: #$color_TableBorder; border-left-width: 0px; border-right-width: 1px; border-top-width: 0px; border-bottom-width: 1px; padding: 1px 2px 1px 1px; font: 11px verdana, arial, helvetica, sans-serif; text-align:center; color: #$color_titletext; }
  600. th.aws    { border-color: #$color_TableBorder; border-left-width: 0px; border-right-width: 1px; border-top-width: 0px; border-bottom-width: 1px; padding: 1px 2px 1px 1px; font-size: 13px; font-weight: bold; }
  601. td        { border-color: #$color_TableBorder; border-left-width: 0px; border-right-width: 1px; border-top-width: 0px; border-bottom-width: 1px; padding: 1px 1px 1px 1px; font: 11px verdana, arial, helvetica, sans-serif; text-align:center; color: #$color_text; }
  602. td.aws    { border-color: #$color_TableBorder; border-left-width: 0px; border-right-width: 1px; border-top-width: 0px; border-bottom-width: 1px; padding: 1px 1px 1px 1px; font: 11px verdana, arial, helvetica, sans-serif; text-align:$dir; color: #$color_text; }
  603. td.awsm    { border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; padding: 0px 0px 0px 0px; font: 11px verdana, arial, helvetica, sans-serif; text-align:$dir; color: #$color_text; }
  604. b { font-weight: bold; }
  605. a { font: 11px verdana, arial, helvetica, sans-serif; }
  606. a:link    { color: #$color_link; text-decoration: none; }
  607. a:visited { color: #$color_link; text-decoration: none; }
  608. a:hover   { color: #$color_hover; text-decoration: underline; }
  609. EOF
  610.             # Call to plugins' function AddHTMLStyles
  611.             foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLStyles'}})  {
  612.                 my $function="AddHTMLStyles_$pluginname()";
  613.                 eval("$function");
  614.             }
  615.     
  616.             if ($BuildReportFormat eq 'xhtml' || $BuildReportFormat eq 'xml') { print ($ENV{'HTTP_USER_AGENT'}=~/Firebird/i?"//-->\n":"]]>\n"); }
  617.             else { print "//-->\n"; }
  618.             print "</style>\n";
  619.  
  620.             if ($StyleSheet) {
  621.                 print "<link rel=\"stylesheet\" href=\"$StyleSheet\" />\n";
  622.             }
  623.         }
  624.         print "</head>\n\n";
  625.         if ($FrameName ne 'index') {
  626.             print "<body style=\"margin-top: 0px\"";
  627.              if ($FrameName eq 'mainleft') { print " class=\"aws_bodyl\""; }
  628.              print ">\n";
  629.         }
  630.     }
  631.     $HeaderHTMLSent++;
  632. }
  633.  
  634. #------------------------------------------------------------------------------
  635. # Function:        Write on ouput end of HTML page
  636. # Parameters:    0|1 (0=no list plugins,1=list plugins)
  637. # Input:        %HTMLOutput $HTMLEndSection $FrameName $BuildReportFormat
  638. # Output:        None
  639. # Return:        None
  640. #------------------------------------------------------------------------------
  641. sub html_end {
  642.     my $listplugins=shift||0;
  643.     if (scalar keys %HTMLOutput) {
  644.  
  645.         # Call to plugins' function AddHTMLBodyFooter
  646.         foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLBodyFooter'}})  {
  647.             my $function="AddHTMLBodyFooter_$pluginname()";
  648.             eval("$function");
  649.         }
  650.  
  651.         if ($FrameName ne 'index' && $FrameName ne 'mainleft') {
  652.             print "$Center<br /><br />\n";
  653.             print "<span dir=\"ltr\" style=\"font: 11px verdana, arial, helvetica; color: #$color_text;\">";
  654.             print "<b>Advanced Web Statistics $VERSION</b> - <a href=\"http://awstats.sourceforge.net\" target=\"awstatshome\">Created by $PROG";
  655.             if ($listplugins) {
  656.                 my $atleastoneplugin=0;
  657.                 foreach my $pluginname (keys %{$PluginsLoaded{'init'}}) {
  658.                     if (! $atleastoneplugin) { $atleastoneplugin=1; print " (with plugin "; }
  659.                     else { print ", "; }
  660.                     print "$pluginname";
  661.                 }
  662.                 if ($atleastoneplugin) { print ")"; }
  663.             }
  664.             print "</a></span><br />\n";
  665.             if ($HTMLEndSection) { print "<br />\n$HTMLEndSection\n"; }
  666.         }
  667.         print "\n";
  668.         if ($FrameName ne 'index') {
  669.             if ($FrameName ne 'mainleft' && $BuildReportFormat eq 'html') { print "<br />\n"; }
  670.             print "</body>\n";
  671.         }
  672.         print "</html>\n";
  673. #        print "<!-- NEW PAGE --><!-- NEW SHEET -->\n";
  674.     }
  675. }
  676.  
  677. #------------------------------------------------------------------------------
  678. # Function:        Print on stdout tab header of a chart
  679. # Parameters:    $title $tooltipnb [$width percentage of chart title]
  680. # Input:        None
  681. # Output:        None
  682. # Return:        None
  683. #------------------------------------------------------------------------------
  684. sub tab_head {
  685.     my $title=shift;
  686.     my $tooltipnb=shift;
  687.     my $width=shift||70;
  688.     my $class=shift;
  689.     if ($width == 70 && $QueryString =~ /buildpdf/i) { print "<table class=\"aws_border\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" width=\"800\">\n"; }
  690.     else { print "<table class=\"aws_border\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" width=\"100%\">\n"; }
  691.  
  692.     if ($tooltipnb) {
  693.         print "<tr><td class=\"aws_title\" width=\"$width%\"".Tooltip($tooltipnb,$tooltipnb).">$title </td>";
  694.     }
  695.     else {
  696.         print "<tr><td class=\"aws_title\" width=\"$width%\">$title </td>";
  697.     }
  698.     print "<td class=\"aws_blank\"> </td></tr>\n";
  699.     print "<tr><td colspan=\"2\">\n";
  700.     if ($width == 70 && $QueryString =~ /buildpdf/i) { print "<table class=\"aws_data $class\" border=\"2\" bordercolor=\"#$color_TableBorder\" cellpadding=\"2\" cellspacing=\"0\" width=\"796\">\n"; }
  701.     else { print "<table class=\"aws_data $class\" border=\"2\" bordercolor=\"#$color_TableBorder\" cellpadding=\"2\" cellspacing=\"0\" width=\"100%\">\n"; }
  702. }
  703.  
  704. #------------------------------------------------------------------------------
  705. # Function:        Print on stdout tab ender of a chart
  706. # Parameters:    None
  707. # Input:        None
  708. # Output:        None
  709. # Return:        None
  710. #------------------------------------------------------------------------------
  711. sub tab_end {
  712.     my $string=shift;
  713.     print "</table></td></tr></table>";
  714.     if ($string) { print "<span style=\"font: 11px verdana, arial, helvetica;\">$string</span><br />\n"; }
  715.     print "<br />\n\n";
  716. }
  717.  
  718. #------------------------------------------------------------------------------
  719. # Function:        Write error message and exit
  720. # Parameters:    $message $secondmessage $thirdmessage $donotshowsetupinfo
  721. # Input:        $HeaderHTTPSent $HeaderHTMLSent %HTMLOutput $LogSeparator $LogFormat
  722. # Output:        None
  723. # Return:        None
  724. #------------------------------------------------------------------------------
  725. sub error {
  726.     my $message=shift||''; if (scalar keys %HTMLOutput) { $message =~ s/\</</g; $message =~ s/\>/>/g; }
  727.     my $secondmessage=shift||'';
  728.     my $thirdmessage=shift||'';
  729.     my $donotshowsetupinfo=shift||0;
  730.  
  731.     if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); }
  732.     if (! $HeaderHTMLSent && scalar keys %HTMLOutput)     { print "<html><body>\n"; $HeaderHTMLSent=1; }
  733.     if ($Debug) { debug("$message $secondmessage $thirdmessage",1); }
  734.     my $tagbold=''; my $tagunbold=''; my $tagbr=''; my $tagfontred=''; my $tagfontgrey=''; my $tagunfont='';
  735.     if (scalar keys %HTMLOutput) {
  736.         $tagbold='<b>'; $tagunbold='</b>'; $tagbr='<br />';
  737.         $tagfontred='<span style="color: #880000">';
  738.         $tagfontgrey='<span style="color: #888888">';
  739.         $tagunfont='</span>';
  740.     }
  741.     if (! $ErrorMessages && $message =~ /^Format error$/i) {
  742.         # Files seems to have bad format
  743.         if (scalar keys %HTMLOutput) { print "<br /><br />\n"; }
  744.         if ($message !~ $LogSeparator) {
  745.             # Bad LogSeparator parameter
  746.             print "${tagfontred}AWStats did not found the ${tagbold}LogSeparator${tagunbold} in your log records.${tagbr}${tagunfont}\n";
  747.         }
  748.         else {
  749.             # Bad LogFormat parameter
  750.             print "AWStats did not find any valid log lines that match your ${tagbold}LogFormat${tagunbold} parameter, in the ${NbOfLinesForCorruptedLog}th first non commented lines read of your log.${tagbr}\n";
  751.             print "${tagfontred}Your log file ${tagbold}$thirdmessage${tagunbold} must have a bad format or ${tagbold}LogFormat${tagunbold} parameter setup does not match this format.${tagbr}${tagbr}${tagunfont}\n";
  752.             print "Your AWStats ${tagbold}LogFormat${tagunbold} parameter is:\n";
  753.             print "${tagbold}$LogFormat${tagunbold}${tagbr}\n";
  754.             print "This means each line in your web server log file need to have ";
  755.             if ($LogFormat == 1) {
  756.                 print "${tagbold}\"combined log format\"${tagunbold} like this:${tagbr}\n";
  757.                 print (scalar keys %HTMLOutput?"$tagfontgrey<i>":"");
  758.                 print "111.22.33.44 - - [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234 \"http://www.fromserver.com/from.htm\" \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\"\n";
  759.                 print (scalar keys %HTMLOutput?"</i>$tagunfont${tagbr}${tagbr}\n":"");
  760.             }
  761.             if ($LogFormat == 2) {
  762.                 print "${tagbold}\"MSIE Extended W3C log format\"${tagunbold} like this:${tagbr}\n";
  763.                 print (scalar keys %HTMLOutput?"$tagfontgrey<i>":"");
  764.                 print "date time c-ip c-username cs-method cs-uri-sterm sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)\n";
  765.                 print (scalar keys %HTMLOutput?"</i>$tagunfont${tagbr}${tagbr}\n":"");
  766.             }
  767.             if ($LogFormat == 3) {
  768.                 print "${tagbold}\"WebStar native log format\"${tagunbold}${tagbr}\n";
  769.             }
  770.             if ($LogFormat == 4) {
  771.                 print "${tagbold}\"common log format\"${tagunbold} like this:${tagbr}\n";
  772.                 print (scalar keys %HTMLOutput?"$tagfontgrey<i>":"");
  773.                 print "111.22.33.44 - - [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234\n";
  774.                 print (scalar keys %HTMLOutput?"</i>$tagunfont${tagbr}${tagbr}\n":"");
  775.             }
  776.             if ($LogFormat == 5) {
  777.                 print "${tagbold}\"ISA native log format\"${tagunbold}${tagbr}\n";
  778.             }
  779.             if ($LogFormat == 6) {
  780.                 print "${tagbold}\"Lotus Notes/Lotus Domino\"${tagunbold}${tagbr}\n";
  781.                 print (scalar keys %HTMLOutput?"$tagfontgrey<i>":"");
  782.                 print "111.22.33.44 - Firstname Middlename Lastname [10/Jan/2001:02:14:14 +0200] \"GET / HTTP/1.1\" 200 1234 \"http://www.fromserver.com/from.htm\" \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\"\n";
  783.                 print (scalar keys %HTMLOutput?"</i></span>${tagbr}${tagbr}\n":"");
  784.             }
  785.             if ($LogFormat !~ /^[1-6]$/) {
  786.                 print "the following personalized log format:${tagbr}\n";
  787.                 print (scalar keys %HTMLOutput?"$tagfontgrey<i>":"");
  788.                 print "$LogFormat\n";
  789.                 print (scalar keys %HTMLOutput?"</i>$tagunfont${tagbr}${tagbr}\n":"");
  790.             }
  791.             print "And this is a sample of records AWStats found in your log file (the record number $NbOfLinesForCorruptedLog in your log):\n";
  792.             print (scalar keys %HTMLOutput?"<br />$tagfontgrey<i>":"");
  793.             print "$secondmessage";
  794.             print (scalar keys %HTMLOutput?"</i>$tagunfont${tagbr}${tagbr}":"");
  795.             print "\n";
  796.         }
  797.         #print "Note: If your $NbOfLinesForCorruptedLog first lines in your log files are wrong because of ";
  798.         #print "a worm virus attack, you can increase the NbOfLinesForCorruptedLog parameter in config file.\n";
  799.         #print "\n";
  800.     }
  801.     else {
  802.         print (scalar keys %HTMLOutput?"<br />$tagfontred\n":"");
  803.         print ($ErrorMessages?"$ErrorMessages":"Error: $message");
  804.         print (scalar keys %HTMLOutput?"\n</span><br />":"");
  805.         print "\n";
  806.     }
  807.     if (! $ErrorMessages && ! $donotshowsetupinfo) {
  808.         if ($message =~ /Couldn.t open config file/i) {
  809.             my $dir=$DIR;
  810.             if ($dir =~ /^\./) { $dir.='/../..'; }
  811.             else { $dir =~ s/[\\\/]?wwwroot[\/\\]cgi-bin[\\\/]?//; }
  812.             print "${tagbr}\n";
  813.             if ($ENV{'GATEWAY_INTERFACE'}) {
  814.                 print "- ${tagbold}Did you use the correct URL ?${tagunbold}${tagbr}\n";
  815.                 print "Example: http://localhost/awstats/awstats.pl?config=mysite${tagbr}\n";
  816.                 print "Example: http://127.0.0.1/cgi-bin/awstats.pl?config=mysite${tagbr}\n";
  817.             } else {
  818.                 print "- ${tagbold}Did you use correct config parameter ?${tagunbold}${tagbr}\n";
  819.                 print "Example: If your config file is awstats.mysite.conf, use -config=mysite\n";
  820.             }
  821.             print "- ${tagbold}Did you create your config file 'awstats.$SiteConfig.conf' ?${tagunbold}${tagbr}\n";
  822.             print "If not, you can run \"$dir/tools/configure.pl\"\nfrom command line, or create it manually.${tagbr}\n";
  823.             print "${tagbr}\n";
  824.         }
  825.         else { print "${tagbr}${tagbold}Setup (".($FileConfig?"'".$FileConfig."'":"Config")." file, web server or permissions) may be wrong.${tagunbold}${tagbr}\n"; }
  826.         print "Check config file, permissions and AWStats documentation (in 'docs' directory).\n";
  827.     }
  828.     # Remove lock if not a lock message 
  829.     if ($EnableLockForUpdate && $message !~ /lock file/) { &Lock_Update(0); }
  830.     if (scalar keys %HTMLOutput) { print "</body></html>\n"; }
  831.     exit 1;
  832. }
  833.  
  834. #------------------------------------------------------------------------------
  835. # Function:        Write a warning message
  836. # Parameters:    $message
  837. # Input:        $HeaderHTTPSent $HeaderHTMLSent $WarningMessage %HTMLOutput
  838. # Output:        None
  839. # Return:        None
  840. #------------------------------------------------------------------------------
  841. sub warning {
  842.     my $messagestring=shift;
  843.  
  844.     if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); }
  845.     if (! $HeaderHTMLSent) { html_head(); }
  846.     if ($Debug) { debug("$messagestring",1); }
  847.     if ($WarningMessages) {
  848.         if (scalar keys %HTMLOutput) {
  849.             $messagestring =~ s/\n/\<br\>/g;
  850.             print "$messagestring<br />\n";
  851.         }
  852.         else {
  853.             print "$messagestring\n";
  854.         }
  855.     }
  856. }
  857.  
  858. #------------------------------------------------------------------------------
  859. # Function:     Write debug message and exit
  860. # Parameters:   $string $level
  861. # Input:        %HTMLOutput  $Debug=required level  $DEBUGFORCED=required level forced
  862. # Output:        None
  863. # Return:        None
  864. #------------------------------------------------------------------------------
  865. sub debug {
  866.     my $level = $_[1] || 1;
  867.  
  868.     if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); }    # To send the HTTP header and see debug
  869.     if ($level <= $DEBUGFORCED) {
  870.         my $debugstring = $_[0];
  871.         if (! $DebugResetDone) { open(DEBUGFORCEDFILE,"debug.log"); close DEBUGFORCEDFILE; chmod 0666,"debug.log"; $DebugResetDone=1; }
  872.         open(DEBUGFORCEDFILE,">>debug.log");
  873.         print DEBUGFORCEDFILE localtime(time)." - $$ - DEBUG $level - $debugstring\n";
  874.         close DEBUGFORCEDFILE;
  875.     }
  876.     if ($DebugMessages && $level <= $Debug) {
  877.         my $debugstring = $_[0];
  878.         if (scalar keys %HTMLOutput) { $debugstring =~ s/^ /   /; $debugstring .= "<br />"; }
  879.         print localtime(time)." - DEBUG $level - $debugstring\n";
  880.     }
  881. }
  882.  
  883. #------------------------------------------------------------------------------
  884. # Function:     Optimize an array removing duplicate entries
  885. # Parameters:    @Array notcasesensitive=0|1
  886. # Input:        None
  887. # Output:        None
  888. # Return:        None
  889. #------------------------------------------------------------------------------
  890. sub OptimizeArray {
  891.     my $array=shift;
  892.     my @arrayunreg=map{if (/\(\?[-\w]*:(.*)\)/) { $1 } } @$array;
  893.     my $notcasesensitive=shift;
  894.     my $searchlist=0;
  895.     if ($Debug) { debug("OptimizeArray (notcasesensitive=$notcasesensitive)",4); }
  896.     while ($searchlist>-1 && @arrayunreg) {
  897.         my $elemtoremove=-1;
  898.         OPTIMIZELOOP:
  899.         foreach my $i ($searchlist..(scalar @arrayunreg)-1) {
  900.             # Search if $i elem is already treated by another elem
  901.             foreach my $j (0..(scalar @arrayunreg)-1) {
  902.                 if ($i == $j) { next; }
  903.                 my $parami=$notcasesensitive?lc($arrayunreg[$i]):$arrayunreg[$i];
  904.                 my $paramj=$notcasesensitive?lc($arrayunreg[$j]):$arrayunreg[$j];
  905.                 if ($Debug) { debug(" Compare $i ($parami) to $j ($paramj)",4); }
  906.                 if (index($parami,$paramj)>-1) {
  907.                     if ($Debug) { debug(" Elem $i ($arrayunreg[$i]) already treated with elem $j ($arrayunreg[$j])",4); }
  908.                     $elemtoremove=$i;
  909.                     last OPTIMIZELOOP;
  910.                 }
  911.             }
  912.         }
  913.         if ($elemtoremove > -1) {
  914.             if ($Debug) { debug(" Remove elem $elemtoremove - $arrayunreg[$elemtoremove]",4); }
  915.             splice @arrayunreg, $elemtoremove, 1;
  916.             $searchlist=$elemtoremove;
  917.         }
  918.         else {
  919.             $searchlist=-1;
  920.         }
  921.     }
  922.     if ($notcasesensitive) { return map{qr/$_/i} @arrayunreg; }
  923.     return map{qr/$_/} @arrayunreg;
  924. }
  925.  
  926. #------------------------------------------------------------------------------
  927. # Function:     Check if parameter is in SkipDNSLookupFor array
  928. # Parameters:    ip @SkipDNSLookupFor (a NOT case sensitive precompiled regex array)
  929. # Return:        0 Not found, 1 Found
  930. #------------------------------------------------------------------------------
  931. sub SkipDNSLookup {
  932.     foreach (@SkipDNSLookupFor) { if ($_[0] =~ /$_/) { return 1; } }
  933.     0; # Not in @SkipDNSLookupFor
  934. }
  935.  
  936. #------------------------------------------------------------------------------
  937. # Function:     Check if parameter is in SkipHosts array
  938. # Parameters:    host @SkipHosts (a NOT case sensitive precompiled regex array)
  939. # Return:        0 Not found, 1 Found
  940. #------------------------------------------------------------------------------
  941. sub SkipHost {
  942.     foreach (@SkipHosts) { if ($_[0] =~ /$_/) { return 1; } }
  943.     0; # Not in @SkipHosts
  944. }
  945.  
  946. #------------------------------------------------------------------------------
  947. # Function:     Check if parameter is in SkipUserAgents array
  948. # Parameters:    useragent @SkipUserAgents (a NOT case sensitive precompiled regex array)
  949. # Return:        0 Not found, 1 Found
  950. #------------------------------------------------------------------------------
  951. sub SkipUserAgent {
  952.     foreach (@SkipUserAgents) { if ($_[0] =~ /$_/) { return 1; } }
  953.     0; # Not in @SkipUserAgent
  954. }
  955.  
  956. #------------------------------------------------------------------------------
  957. # Function:     Check if parameter is in SkipFiles array
  958. # Parameters:    url @SkipFiles (a NOT case sensitive precompiled regex array)
  959. # Return:        0 Not found, 1 Found
  960. #------------------------------------------------------------------------------
  961. sub SkipFile {
  962.     foreach (@SkipFiles) { if ($_[0] =~ /$_/) { return 1; } }
  963.     0; # Not in @SkipFiles
  964. }
  965.  
  966. #------------------------------------------------------------------------------
  967. # Function:     Check if parameter is in OnlyHosts array
  968. # Parameters:    host @OnlyHosts (a NOT case sensitive precompiled regex array)
  969. # Return:        0 Not found, 1 Found
  970. #------------------------------------------------------------------------------
  971. sub OnlyHost {
  972.     foreach (@OnlyHosts) { if ($_[0] =~ /$_/) { return 1; } }
  973.     0; # Not in @OnlyHosts
  974. }
  975.  
  976. #------------------------------------------------------------------------------
  977. # Function:     Check if parameter is in OnlyUserAgents array
  978. # Parameters:    useragent @OnlyUserAgents (a NOT case sensitive precompiled regex array)
  979. # Return:        0 Not found, 1 Found
  980. #------------------------------------------------------------------------------
  981. sub OnlyUserAgent {
  982.     foreach (@OnlyUserAgents) { if ($_[0] =~ /$_/) { return 1; } }
  983.     0; # Not in @OnlyHosts
  984. }
  985.  
  986. #------------------------------------------------------------------------------
  987. # Function:     Check if parameter is in OnlyFiles array
  988. # Parameters:    url @OnlyFiles (a NOT case sensitive precompiled regex array)
  989. # Return:        0 Not found, 1 Found
  990. #------------------------------------------------------------------------------
  991. sub OnlyFile {
  992.     foreach (@OnlyFiles) { if ($_[0] =~ /$_/) { return 1; } }
  993.     0; # Not in @OnlyFiles
  994. }
  995.  
  996. #------------------------------------------------------------------------------
  997. # Function:     Return day of week of a day
  998. # Parameters:    $day $month $year
  999. # Return:        0-6
  1000. #------------------------------------------------------------------------------
  1001. sub DayOfWeek {
  1002.     my ($day, $month, $year) = @_;
  1003.     if ($Debug) { debug("DayOfWeek for $day $month $year",4); }
  1004.     if ($month < 3) {  $month += 10;  $year--; }
  1005.     else { $month -= 2; }
  1006.     my $cent = sprintf("%1i",($year/100));
  1007.     my $y = ($year % 100);
  1008.     my $dw = (sprintf("%1i",(2.6*$month)-0.2) + $day + $y + sprintf("%1i",($y/4)) + sprintf("%1i",($cent/4)) - (2*$cent)) % 7;
  1009.     $dw += 7 if ($dw<0);
  1010.     if ($Debug) { debug(" is $dw",4); }
  1011.     return $dw;
  1012. }
  1013.  
  1014. #------------------------------------------------------------------------------
  1015. # Function:     Return 1 if a date exists
  1016. # Parameters:    $day $month $year
  1017. # Return:        1 if date exists else 0
  1018. #------------------------------------------------------------------------------
  1019. sub DateIsValid {
  1020.     my ($day, $month, $year) = @_;
  1021.     if ($Debug) { debug("DateIsValid for $day $month $year",4); }
  1022.     if ($day < 1)  { return 0; }
  1023.     if ($day > 31) { return 0; }
  1024.     if ($month==4 || $month==6 || $month==9 || $month==11) {
  1025.         if ($day > 30) { return 0; }
  1026.     }
  1027.     elsif ($month==2) {
  1028.         my $leapyear=($year%4==0?1:0);                        # A leap year every 4 years
  1029.         if ($year%100==0 && $year%400!=0) { $leapyear=0; }    # Except if year is 100x and not 400x
  1030.         if ($day > (28+$leapyear)) { return 0; }
  1031.     }
  1032.     return 1;
  1033. }
  1034.  
  1035. #------------------------------------------------------------------------------
  1036. # Function:     Return string of visit duration
  1037. # Parameters:    $starttime $endtime
  1038. # Input:        None
  1039. # Output:        None
  1040. # Return:        A string that identify the visit duration range
  1041. #------------------------------------------------------------------------------
  1042. sub GetSessionRange {
  1043.     my $starttime = my $endtime;
  1044.     if (shift =~ /(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) { $starttime = Time::Local::timelocal($6,$5,$4,$3,$2-1,$1); }
  1045.     if (shift =~ /(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) { $endtime = Time::Local::timelocal($6,$5,$4,$3,$2-1,$1); }
  1046.     my $delay=$endtime-$starttime;
  1047.     if ($Debug) { debug("GetSessionRange $endtime - $starttime = $delay",4); }
  1048.     if ($delay <= 30) { return $SessionsRange[0]; }
  1049.     if ($delay > 30 && $delay <= 120) { return $SessionsRange[1]; }
  1050.     if ($delay > 120 && $delay <= 300) { return $SessionsRange[2]; }
  1051.     if ($delay > 300 && $delay <= 900) { return $SessionsRange[3]; }
  1052.     if ($delay > 900 && $delay <= 1800) { return $SessionsRange[4]; }
  1053.     if ($delay > 1800 && $delay <= 3600) { return $SessionsRange[5]; }
  1054.     if ($delay > 3600) { return $SessionsRange[6]; }
  1055.     return "error";
  1056. }
  1057.  
  1058. #------------------------------------------------------------------------------
  1059. # Function:     Read config file
  1060. # Parameters:    None or configdir to scan
  1061. # Input:        $DIR $PROG $SiteConfig
  1062. # Output:        Global variables
  1063. # Return:        -
  1064. #------------------------------------------------------------------------------
  1065. sub Read_Config {
  1066.     # Check config file in common possible directories :
  1067.     # Windows :                                   "$DIR" (same dir than awstats.pl)
  1068.     # Standard, Mandrake and Debian package :    "/etc/awstats"
  1069.     # Other possible directories :                "/usr/local/etc/awstats", "/etc"
  1070.     # FHS standard, Suse package :                 "/etc/opt/awstats"
  1071.     my $configdir=shift;
  1072.     my @PossibleConfigDir=();
  1073.  
  1074.     if ($configdir) { @PossibleConfigDir=("$configdir"); }
  1075.     else { @PossibleConfigDir=("$DIR","/etc/awstats","/usr/local/etc/awstats","/etc","/etc/opt/awstats"); }
  1076.  
  1077.     # Open config file
  1078.     $FileConfig=$FileSuffix='';
  1079.     foreach (@PossibleConfigDir) {
  1080.         my $searchdir=$_;
  1081.         if ($searchdir && $searchdir !~ /[\\\/]$/) { $searchdir .= "/"; }
  1082.         if (open(CONFIG,"$searchdir$PROG.$SiteConfig.conf"))     { $FileConfig="$searchdir$PROG.$SiteConfig.conf"; $FileSuffix=".$SiteConfig"; last; }
  1083.         if (open(CONFIG,"$searchdir$PROG.conf"))                  { $FileConfig="$searchdir$PROG.conf"; $FileSuffix=''; last; }
  1084.     }
  1085.     if (! $FileConfig) { error("Couldn't open config file \"$PROG.$SiteConfig.conf\" nor \"$PROG.conf\" after searching in path \"".join(',',@PossibleConfigDir)."\": $!"); }
  1086.  
  1087.     # Analyze config file content and close it
  1088.     &Parse_Config( *CONFIG , 1 , $FileConfig);
  1089.     close CONFIG;
  1090.     
  1091.     # If parameter NotPageList not found, init for backward compatibility
  1092.     if (! $FoundNotPageList) {
  1093.         %NotPageList=('css'=>1,'js'=>1,'class'=>1,'gif'=>1,'jpg'=>1,'jpeg'=>1,'png'=>1,'bmp'=>1);
  1094.     }
  1095.     # If parameter ValidHTTPCodes empty, init for backward compatibility
  1096.     if (! scalar keys %ValidHTTPCodes) { $ValidHTTPCodes{"200"}=$ValidHTTPCodes{"304"}=1; }
  1097.     # If parameter ValidSMTPCodes empty, init for backward compatibility
  1098.     if (! scalar keys %ValidSMTPCodes) { $ValidSMTPCodes{"1"}=$ValidSMTPCodes{"250"}=1; }
  1099. }
  1100.  
  1101. #------------------------------------------------------------------------------
  1102. # Function:     Parse content of a config file
  1103. # Parameters:    opened file handle, depth level, file name
  1104. # Input:        -
  1105. # Output:        Global variables
  1106. # Return:        -
  1107. #------------------------------------------------------------------------------
  1108. sub Parse_Config {
  1109.     my ( $confighandle ) = $_[0];
  1110.     my $level = $_[1];
  1111.     my $configFile = $_[2];
  1112.     my $versionnum=0;
  1113.     my $conflinenb=0;
  1114.     
  1115.     if ($level > 10) { error("$PROG can't read down more than 10 level of includes. Check that no 'included' config files include their parent config file (this cause infinite loop)."); }
  1116.  
  1117.        while (<$confighandle>) {
  1118.         chomp $_; s/\r//;
  1119.         $conflinenb++;
  1120.  
  1121.         # Extract version from first line
  1122.         if (! $versionnum && $_ =~ /^# AWSTATS CONFIGURE FILE (\d+).(\d+)/i) {
  1123.             $versionnum=($1*1000)+$2;
  1124.             #if ($Debug) { debug(" Configure file version is $versionnum",1); }
  1125.             next;
  1126.         }
  1127.  
  1128.         if ($_ =~ /^\s*$/) { next; }
  1129.  
  1130.         # Check includes
  1131.         if ($_ =~ /^Include "([^\"]+)"/ || $_ =~ /^#include "([^\"]+)"/) {    # #include kept for backward compatibility
  1132.             my $includeFile = $1;
  1133.             if ($Debug) { debug("Found an include : $includeFile",2); }
  1134.             if ( $includeFile !~ /^[\\\/]/ ) {
  1135.                 # Correct relative include files
  1136.                 if ($FileConfig =~ /^(.*[\\\/])[^\\\/]*$/) { $includeFile = "$1$includeFile"; }
  1137.             }
  1138.             if ($level > 1) {
  1139.                 warning("Warning: Perl versions before 5.6 cannot handle nested includes");
  1140.                 next;
  1141.             }
  1142.             if ( open( CONFIG_INCLUDE, $includeFile ) ) {
  1143.                 &Parse_Config( *CONFIG_INCLUDE , $level+1, $includeFile);
  1144.                 close( CONFIG_INCLUDE );
  1145.             }
  1146.             else {
  1147.                 error("Could not open include file: $includeFile" );
  1148.             }
  1149.             next;
  1150.         }
  1151.  
  1152.         # Remove comments
  1153.         if ($_ =~ /^\s*#/) { next; }
  1154.         $_ =~ s/\s#.*$//;
  1155.  
  1156.         # Extract param and value
  1157.         my ($param,$value)=split(/=/,$_,2);
  1158.         $param =~ s/^\s+//; $param =~ s/\s+$//;
  1159.  
  1160.         # If not a param=value, try with next line
  1161.         if (! $param) { warning("Warning: Syntax error line $conflinenb in file '$configFile'. Config line is ignored."); next; }
  1162.         if (! defined $value) { warning("Warning: Syntax error line $conflinenb in file '$configFile'. Config line is ignored."); next; }
  1163.  
  1164.         if ($value) {
  1165.             $value =~ s/^\s+//; $value =~ s/\s+$//;
  1166.             $value =~ s/^\"//; $value =~ s/\";?$//;
  1167.             # Replace __MONENV__ with value of environnement variable MONENV
  1168.             # Must be able to replace __VAR_1____VAR_2__
  1169.             while ($value =~ /__([^\s_]+(?:_[^\s_]+)*)__/) { my $var=$1; $value =~ s/__${var}__/$ENV{$var}/g; }
  1170.         }
  1171.  
  1172.         # Initialize parameter for (param,value)
  1173.         if ($param =~ /^LogFile/) {
  1174.             if ($QueryString !~ /logfile=([^\s&]+)/i) { $LogFile=$value; }
  1175.             next;
  1176.             }
  1177.         if ($param =~ /^DirIcons/) {
  1178.             if ($QueryString !~ /diricons=([^\s&]+)/i) { $DirIcons=$value; }
  1179.             next;
  1180.             }
  1181.         if ($param =~ /^SiteDomain/)            {
  1182.             # No regex test as SiteDomain is always exact value
  1183.             $SiteDomain=$value;
  1184.             next;
  1185.             }
  1186.         if ($param =~ /^HostAliases/) {
  1187.             foreach my $elem (split(/\s+/,$value))    {
  1188.                 if ($elem =~ s/^\@//) { # If list of hostaliases in a file
  1189.                     open(DATAFILE,"<$elem") || error("Failed to open file '$elem' declared in HostAliases parameter");
  1190.                     my @val=map(/^(.*)$/i,<DATAFILE>);
  1191.                     push @HostAliases, map{qr/^$_$/i} @val;
  1192.                     close(DATAFILE);
  1193.                 }
  1194.                 else {
  1195.                     if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1196.                     else { $elem='^'.quotemeta($elem).'$'; }
  1197.                     if ($elem) { push @HostAliases, qr/$elem/i; }
  1198.                 }
  1199.             }
  1200.             next;
  1201.             }
  1202.         # Special optional setup params
  1203.         if ($param =~ /^SkipDNSLookupFor/) {
  1204.             foreach my $elem (split(/\s+/,$value))    {
  1205.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1206.                 else { $elem='^'.quotemeta($elem).'$'; }
  1207.                 if ($elem) { push @SkipDNSLookupFor, qr/$elem/i; }
  1208.             }
  1209.             next;
  1210.             }
  1211.         if ($param =~ /^AllowAccessFromWebToFollowingAuthenticatedUsers/) {
  1212.             foreach (split(/\s+/,$value))    { push @AllowAccessFromWebToFollowingAuthenticatedUsers,$_; }
  1213.             next;
  1214.             }
  1215.         if ($param =~ /^DefaultFile/)           {
  1216.             foreach my $elem (split(/\s+/,$value))    {    
  1217.                 # No REGEX for this option
  1218.                 #if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1219.                 #else { $elem='^'.quotemeta($elem).'$'; }
  1220.                 if ($elem) { push @DefaultFile,$elem; }
  1221.             }
  1222.             next;
  1223.             }
  1224.         if ($param =~ /^SkipHosts/) {
  1225.             foreach my $elem (split(/\s+/,$value))    {
  1226.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1227.                 else { $elem='^'.quotemeta($elem).'$'; }
  1228.                 if ($elem) { push @SkipHosts, qr/$elem/i; }
  1229.             }
  1230.             next;
  1231.             }
  1232.         if ($param =~ /^SkipUserAgents/) {
  1233.             foreach my $elem (split(/\s+/,$value))    {
  1234.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1235.                 else { $elem='^'.quotemeta($elem).'$'; }
  1236.                 if ($elem) { push @SkipUserAgents, qr/$elem/i; }
  1237.             }
  1238.             next;
  1239.             }
  1240.         if ($param =~ /^SkipFiles/) {
  1241.             foreach my $elem (split(/\s+/,$value))    {
  1242.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1243.                 else { $elem='^'.quotemeta($elem).'$'; }
  1244.                 if ($elem) { push @SkipFiles, qr/$elem/i; }
  1245.             }
  1246.             next;
  1247.             }
  1248.         if ($param =~ /^OnlyHosts/) {
  1249.             foreach my $elem (split(/\s+/,$value))    {
  1250.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1251.                 else { $elem='^'.quotemeta($elem).'$'; }
  1252.                 if ($elem) { push @OnlyHosts, qr/$elem/i; }
  1253.             }
  1254.             next;
  1255.             }
  1256.         if ($param =~ /^OnlyUserAgents/) {
  1257.             foreach my $elem (split(/\s+/,$value))    {
  1258.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1259.                 else { $elem='^'.quotemeta($elem).'$'; }
  1260.                 if ($elem) { push @OnlyUserAgents, qr/$elem/i; }
  1261.             }
  1262.             next;
  1263.             }
  1264.         if ($param =~ /^OnlyFiles/) {
  1265.             foreach my $elem (split(/\s+/,$value))    {
  1266.                 if ($elem =~ /^REGEX\[(.*)\]$/i) { $elem=$1; }
  1267.                 else { $elem='^'.quotemeta($elem).'$'; }
  1268.                 if ($elem) { push @OnlyFiles, qr/$elem/i; }
  1269.             }
  1270.             next;
  1271.             }
  1272.         if ($param =~ /^NotPageList/) {
  1273.             foreach (split(/\s+/,$value))    { $NotPageList{$_}=1; }
  1274.             $FoundNotPageList=1;
  1275.             next;
  1276.             }
  1277.         if ($param =~ /^ValidHTTPCodes/) {
  1278.             foreach (split(/\s+/,$value))    { $ValidHTTPCodes{$_}=1; }
  1279.             next;
  1280.             }
  1281.         if ($param =~ /^ValidSMTPCodes/) {
  1282.             foreach (split(/\s+/,$value))    { $ValidSMTPCodes{$_}=1; }
  1283.             next;
  1284.             }
  1285.         if ($param =~ /^URLWithQueryWithOnlyFollowingParameters$/)    {
  1286.             @URLWithQueryWithOnly=split(/\s+/,$value);
  1287.             next;
  1288.             }
  1289.         if ($param =~ /^URLWithQueryWithoutFollowingParameters$/)    {
  1290.             @URLWithQueryWithout=split(/\s+/,$value);
  1291.             next;
  1292.             }
  1293.  
  1294.          # Extra parameters
  1295.          if ($param =~ /^ExtraSectionName(\d+)/)            { $ExtraName[$1]=$value; next; }
  1296.          if ($param =~ /^ExtraSectionCodeFilter(\d+)/)      { @{$ExtraCodeFilter[$1]}=split(/\s+/,$value); next; }
  1297.          if ($param =~ /^ExtraSectionCondition(\d+)/)      { $ExtraCondition[$1]=$value; next; }
  1298.          if ($param =~ /^ExtraSectionStatTypes(\d+)/)    { $ExtraStatTypes[$1]=$value; next; }
  1299.          if ($param =~ /^ExtraSectionFirstColumnTitle(\d+)/)     { $ExtraFirstColumnTitle[$1]=$value; next; }
  1300.          if ($param =~ /^ExtraSectionFirstColumnValues(\d+)/)     { $ExtraFirstColumnValues[$1]=$value; next; }
  1301.          if ($param =~ /^ExtraSectionFirstColumnFormat(\d+)/)     { $ExtraFirstColumnFormat[$1]=$value; next; }
  1302.          if ($param =~ /^ExtraSectionAddAverageRow(\d+)/)     { $ExtraAddAverageRow[$1]=$value; next; }
  1303.          if ($param =~ /^ExtraSectionAddSumRow(\d+)/)     { $ExtraAddSumRow[$1]=$value; next; }
  1304.          if ($param =~ /^MaxNbOfExtra(\d+)/)             { $MaxNbOfExtra[$1]=$value; next; }
  1305.          if ($param =~ /^MinHitExtra(\d+)/)                 { $MinHitExtra[$1]=$value; next; }
  1306.         # Special appearance parameters
  1307.         if ($param =~ /^LoadPlugin/)                      { push @PluginsToLoad, $value; next; }
  1308.         # Other parameter checks we need to put after MaxNbOfExtra and MinHitExtra
  1309.          if ($param =~ /^MaxNbOf(\w+)/)     { $MaxNbOf{$1}=$value; next; }
  1310.          if ($param =~ /^MinHit(\w+)/)     { $MinHit{$1}=$value; next; }
  1311.         # Check if this is a known parameter
  1312. #        if (! $ConfOk{$param}) { error("Unknown config parameter '$param' found line $conflinenb in file \"configFile\""); }
  1313.         # If parameters was not found previously, defined variable with name of param to value
  1314.         $$param=$value;
  1315.     }
  1316.  
  1317.     # For backward compatibility
  1318.     if ($versionnum < 5001) { $BarHeight=$BarHeight>>1; }
  1319.  
  1320.     if ($Debug) { debug("Config file read was \"$configFile\" (level $level)"); }
  1321. }
  1322.  
  1323. #------------------------------------------------------------------------------
  1324. # Function:     Load the reference databases
  1325. # Parameters:    List of files to load
  1326. # Input:        $DIR
  1327. # Output:        Arrays and Hash tables are defined
  1328. # Return:       -
  1329. #------------------------------------------------------------------------------
  1330. sub Read_Ref_Data {
  1331.     # Check lib files in common possible directories :
  1332.     # Windows and standard package:                "$DIR/lib" (lib in same dir than awstats.pl)
  1333.     # Debian package :                            "/usr/share/awstats/lib"
  1334.     my @PossibleLibDir=("$DIR/lib","/usr/share/awstats/lib");
  1335.     my %FilePath=(); my %DirAddedInINC=();
  1336.     my @FileListToLoad=();
  1337.     while (my $file=shift) { push @FileListToLoad, "$file.pm"; }
  1338.     if ($Debug) { debug("Call to Read_Ref_Data with files to load: ".(join(',',@FileListToLoad))); }
  1339.     foreach my $file (@FileListToLoad) {
  1340.         foreach my $dir (@PossibleLibDir) {
  1341.             my $searchdir=$dir;
  1342.             if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; }
  1343.             if (! $FilePath{$file}) {    # To not load twice same file in different path
  1344.                 if (-s "${searchdir}${file}") {
  1345.                     $FilePath{$file}="${searchdir}${file}";
  1346.                     if ($Debug) { debug("Call to Read_Ref_Data [FilePath{$file}=\"$FilePath{$file}\"]"); }
  1347.                     # Note: cygwin perl 5.8 need a push + require file
  1348.                     if (! $DirAddedInINC{"$dir"}) { 
  1349.                         push @INC, "$dir";
  1350.                         $DirAddedInINC{"$dir"}=1;
  1351.                     }
  1352.                     my $loadret=require "$file";
  1353.                     #my $loadret=(require "$FilePath{$file}"||require "${file}");
  1354.                 }
  1355.             }
  1356.         }
  1357.         if (! $FilePath{$file}) {
  1358.             my $filetext=$file; $filetext =~ s/\.pm$//; $filetext =~ s/_/ /g;
  1359.             warning("Warning: Can't read file \"$file\" ($filetext detection will not work correctly).\nCheck if file is in \"".($PossibleLibDir[0])."\" directory and is readable.");
  1360.         }
  1361.     }
  1362.     # Sanity check (if loaded)
  1363.     if ((scalar keys %OSHashID) && @OSSearchIDOrder != scalar keys %OSHashID) { error("Not same number of records of OSSearchIDOrder (".(@OSSearchIDOrder)." entries) and OSHashID (".(scalar keys %OSHashID)." entries) in OS database. Check your file ".$FilePath{"operating_systems.pm"}); }
  1364.     if ((scalar keys %SearchEnginesHashID) && (@SearchEnginesSearchIDOrder_list1+@SearchEnginesSearchIDOrder_list2+@SearchEnginesSearchIDOrder_listgen) != scalar keys %SearchEnginesHashID) { error("Not same number of records of SearchEnginesSearchIDOrder_listx (total is ".(@SearchEnginesSearchIDOrder_list1+@SearchEnginesSearchIDOrder_list2+@SearchEnginesSearchIDOrder_listgen)." entries) and SearchEnginesHashID (".(scalar keys %SearchEnginesHashID)." entries) in Search Engines database. Check your file ".$FilePath{"search_engines.pm"}); }
  1365.     if ((scalar keys %BrowsersHashIDLib) && @BrowsersSearchIDOrder != (scalar keys %BrowsersHashIDLib) - 2) { error("Not same number of records of BrowsersSearchIDOrder (".(@BrowsersSearchIDOrder)." entries) and BrowsersHashIDLib (".((scalar keys %BrowsersHashIDLib) - 2)." entries without msie and netscape) in Browsers database. Check your file ".$FilePath{"browsers.pm"}); }
  1366.     if ((scalar keys %RobotsHashIDLib) && (@RobotsSearchIDOrder_list1+@RobotsSearchIDOrder_list2+@RobotsSearchIDOrder_listgen) != (scalar keys %RobotsHashIDLib) - 1) { error("Not same number of records of RobotsSearchIDOrder_listx (total is ".(@RobotsSearchIDOrder_list1+@RobotsSearchIDOrder_list2+@RobotsSearchIDOrder_listgen)." entries) and RobotsHashIDLib (".((scalar keys %RobotsHashIDLib) - 1)." entries without 'unknown') in Robots database. Check your file ".$FilePath{"robots.pm"}); }
  1367. }
  1368.  
  1369.  
  1370. #------------------------------------------------------------------------------
  1371. # Function:     Get the messages for a specified language
  1372. # Parameters:    LanguageId
  1373. # Input:        $DirLang $DIR
  1374. # Output:        $Message table is defined in memory
  1375. # Return:        None
  1376. #------------------------------------------------------------------------------
  1377. sub Read_Language_Data {
  1378.     # Check lang files in common possible directories :
  1379.     # Windows and standard package:             "$DIR/lang" (lang in same dir than awstats.pl)
  1380.     # Debian package :                            "/usr/share/awstats/lang"
  1381.     my @PossibleLangDir=("$DirLang","$DIR/lang","/usr/share/awstats/lang");
  1382.  
  1383.     my $FileLang='';
  1384.     foreach (@PossibleLangDir) {
  1385.         my $searchdir=$_;
  1386.         if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; }
  1387.         if (open(LANG,"${searchdir}awstats-$_[0].txt")) { $FileLang="${searchdir}awstats-$_[0].txt"; last; }
  1388.     }
  1389.     # If file not found, we try english
  1390.     if (! $FileLang) {
  1391.         foreach (@PossibleLangDir) {
  1392.             my $searchdir=$_;
  1393.             if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; }
  1394.             if (open(LANG,"${searchdir}awstats-en.txt")) { $FileLang="${searchdir}awstats-en.txt"; last; }
  1395.         }
  1396.     }
  1397.     if ($Debug) { debug("Call to Read_Language_Data [FileLang=\"$FileLang\"]"); }
  1398.     if ($FileLang) {
  1399.         my $i = 0;
  1400.         binmode LANG;    # Might avoid 'Malformed UTF-8 errors'
  1401.         my $cregcode=qr/^PageCode=[\t\s\"\']*([\w-]+)/i;
  1402.         my $cregdir=qr/^PageDir=[\t\s\"\']*([\w-]+)/i;
  1403.         my $cregmessage=qr/^Message\d+=/i;
  1404.         while (<LANG>) {
  1405.             chomp $_; s/\r//;
  1406.             if ($_ =~ /$cregcode/o) { $PageCode = $1; }
  1407.             if ($_ =~ /$cregdir/o)  { $PageDir = $1; }
  1408.             if ($_ =~ s/$cregmessage//o) {
  1409.                 $_ =~ s/#.*//;                                # Remove comments
  1410.                 $_ =~ tr/\t /  /s;                            # Change all blanks into " "
  1411.                 $_ =~ s/^\s+//; $_ =~ s/\s+$//;
  1412.                 $_ =~ s/^\"//; $_ =~ s/\"$//;
  1413.                 $Message[$i] = $_;
  1414.                 $i++;
  1415.             }
  1416.         }
  1417.         close(LANG);
  1418.     }
  1419.     else {
  1420.         warning("Warning: Can't find language files for \"$_[0]\". English will be used.");
  1421.     }
  1422.     # Some language string changes
  1423.     if ($LogType eq 'M') {    # For mail
  1424.         $Message[8]=$Message[151];
  1425.         $Message[9]=$Message[152];
  1426.         $Message[57]=$Message[149];
  1427.         $Message[75]=$Message[150];
  1428.     }
  1429.     if ($LogType eq 'F') {    # For web
  1430.  
  1431.     }
  1432. }
  1433.  
  1434.  
  1435. #------------------------------------------------------------------------------
  1436. # Function:     Check if all parameters are correctly defined. If not set them to default.
  1437. # Parameters:    None
  1438. # Input:        All global variables
  1439. # Output:        Change on some global variables
  1440. # Return:        None
  1441. #------------------------------------------------------------------------------
  1442. sub Check_Config {
  1443.     if ($Debug) { debug("Call to Check_Config"); }
  1444.  
  1445.     my %MonthNumLibEn = ("01","Jan","02","Feb","03","Mar","04","Apr","05","May","06","Jun","07","Jul","08","Aug","09","Sep","10","Oct","11","Nov","12","Dec");
  1446.  
  1447.     # Show initial values of main parameters before check
  1448.     if ($Debug) {
  1449.         debug(" LogFile='$LogFile'",2);
  1450.         debug(" LogType='$LogType'",2);
  1451.         debug(" LogFormat='$LogFormat'",2);
  1452.         debug(" LogSeparator='$LogSeparator'",2);
  1453.         debug(" DNSLookup='$DNSLookup'",2);
  1454.         debug(" DirData='$DirData'",2);
  1455.         debug(" DirCgi='$DirCgi'",2);
  1456.         debug(" DirIcons='$DirIcons'",2);
  1457.         debug(" NotPageList ".(join(',',keys %NotPageList)),2);
  1458.         debug(" ValidHTTPCodes ".(join(',',keys %ValidHTTPCodes)),2);
  1459.         debug(" ValidSMTPCodes ".(join(',',keys %ValidSMTPCodes)),2);
  1460.         debug(" UseFramesWhenCGI=$UseFramesWhenCGI",2);
  1461.         debug(" BuildReportFormat=$BuildReportFormat",2);
  1462.         debug(" BuildHistoryFormat=$BuildHistoryFormat",2);
  1463.         debug(" URLWithQueryWithOnlyFollowingParameters=".(join(',',@URLWithQueryWithOnly)),2);
  1464.         debug(" URLWithQueryWithoutFollowingParameters=".(join(',',@URLWithQueryWithout)),2);
  1465.     }
  1466.  
  1467.     # Main section
  1468.     while ($LogFile =~ /%([ymdhwYMDHWNSO]+)-(\(\d+\)|\d+)/) {
  1469.         # Accept tag %xx-dd and %xx-(dd)
  1470.         my $timetag="$1";
  1471.         my $timephase=quotemeta("$2");
  1472.         my $timephasenb="$2"; $timephasenb=~s/[^\d]//g;
  1473.         if ($Debug) { debug(" Found a time tag '$timetag' with a phase of '$timephasenb' hour in log file name",1); }
  1474.         # Get older time
  1475.         my ($oldersec,$oldermin,$olderhour,$olderday,$oldermonth,$olderyear,$olderwday,$olderyday) = localtime($starttime-($timephasenb*3600));
  1476.         my $olderweekofmonth=int($olderday/7);
  1477.         my $olderweekofyear=int(($olderyday-1+6-($olderwday==0?6:$olderwday-1))/7)+1; if ($olderweekofyear > 52) { $olderweekofyear = 1; }
  1478.         my $olderdaymod=$olderday%7;
  1479.         $olderwday++;
  1480.         my $olderns=Time::Local::timegm(0,0,0,$olderday,$oldermonth,$olderyear);
  1481.         if ($olderdaymod <= $olderwday) { if (($olderwday != 7) || ($olderdaymod != 0)) { $olderweekofmonth=$olderweekofmonth+1; } }
  1482.         if ($olderdaymod >  $olderwday) { $olderweekofmonth=$olderweekofmonth+2; }
  1483.         # Change format of time variables
  1484.         $olderweekofmonth = "0$olderweekofmonth";
  1485.         if ($olderweekofyear < 10) { $olderweekofyear = "0$olderweekofyear"; }
  1486.         if ($olderyear < 100) { $olderyear+=2000; } else { $olderyear+=1900; }
  1487.         my $oldersmallyear=$olderyear;$oldersmallyear =~ s/^..//;
  1488.         if (++$oldermonth < 10) { $oldermonth = "0$oldermonth"; }
  1489.         if ($olderday < 10) { $olderday = "0$olderday"; }
  1490.         if ($olderhour < 10) { $olderhour = "0$olderhour"; }
  1491.         if ($oldermin < 10) { $oldermin = "0$oldermin"; }
  1492.         if ($oldersec < 10) { $oldersec = "0$oldersec"; }
  1493.         # Replace tag with new value
  1494.         if ($timetag eq 'YYYY') { $LogFile =~ s/%YYYY-$timephase/$olderyear/ig; next; }
  1495.         if ($timetag eq 'YY')   { $LogFile =~ s/%YY-$timephase/$oldersmallyear/ig; next; }
  1496.         if ($timetag eq 'MM')   { $LogFile =~ s/%MM-$timephase/$oldermonth/ig; next; }
  1497.         if ($timetag eq 'MO')   { $LogFile =~ s/%MO-$timephase/$MonthNumLibEn{$oldermonth}/ig; next; }
  1498.         if ($timetag eq 'DD')   { $LogFile =~ s/%DD-$timephase/$olderday/ig; next; }
  1499.         if ($timetag eq 'HH')   { $LogFile =~ s/%HH-$timephase/$olderhour/ig; next; }
  1500.         if ($timetag eq 'NS')   { $LogFile =~ s/%NS-$timephase/$olderns/ig; next; }
  1501.         if ($timetag eq 'WM')   { $LogFile =~ s/%WM-$timephase/$olderweekofmonth/g; next; }
  1502.         if ($timetag eq 'Wm')   { my $olderweekofmonth0=$olderweekofmonth-1; $LogFile =~ s/%Wm-$timephase/$olderweekofmonth0/g; next; }
  1503.         if ($timetag eq 'WY')   { $LogFile =~ s/%WY-$timephase/$olderweekofyear/g; next; }
  1504.         if ($timetag eq 'Wy')   { my $olderweekofyear0=sprintf("%02d",$olderweekofyear-1); $LogFile =~ s/%Wy-$timephase/$olderweekofyear0/g; next; }
  1505.         if ($timetag eq 'DW')   { $LogFile =~ s/%DW-$timephase/$olderwday/g; next; }
  1506.         if ($timetag eq 'Dw')   { my $olderwday0=$olderwday-1; $LogFile =~ s/%Dw-$timephase/$olderwday0/g; next; }
  1507.         # If unknown tag
  1508.         error("Unknown tag '\%$timetag' in LogFile parameter.");
  1509.     }
  1510.     # Replace %YYYY %YY %MM %DD %HH with current value. Kept for backward compatibility.
  1511.     $LogFile =~ s/%YYYY/$nowyear/ig;
  1512.     $LogFile =~ s/%YY/$nowsmallyear/ig;
  1513.     $LogFile =~ s/%MM/$nowmonth/ig;
  1514.     $LogFile =~ s/%MO/$MonthNumLibEn{$nowmonth}/ig;
  1515.     $LogFile =~ s/%DD/$nowday/ig;
  1516.     $LogFile =~ s/%HH/$nowhour/ig;
  1517.     $LogFile =~ s/%NS/$nowns/ig;
  1518.     $LogFile =~ s/%WM/$nowweekofmonth/g;
  1519.     my $nowweekofmonth0=$nowweekofmonth-1; $LogFile =~ s/%Wm/$nowweekofmonth0/g;
  1520.     $LogFile =~ s/%WY/$nowweekofyear/g;
  1521.     my $nowweekofyear0=$nowweekofyear-1; $LogFile =~ s/%Wy/$nowweekofyear0/g;
  1522.     $LogFile =~ s/%DW/$nowwday/g;
  1523.     my $nowwday0=$nowwday-1; $LogFile =~ s/%Dw/$nowwday0/g;
  1524.     if (! $LogFile)   { error("LogFile parameter is not defined in config/domain file"); }
  1525.     if ($LogType !~ /[WSMF]/i) { $LogType='W'; }
  1526.     $LogFormat =~ s/\\//g;
  1527.     if (! $LogFormat) { error("LogFormat parameter is not defined in config/domain file"); }
  1528.     if ($LogFormat =~ /^\d$/ && $LogFormat !~ /[1-6]/)  { error("LogFormat parameter is wrong in config/domain file. Value is '$LogFormat' (should be 1,2,3,4,5 or a 'personalized AWStats log format string')"); }
  1529.     $LogSeparator||="\\s";
  1530.     $DirData||='.';
  1531.     $DirCgi||='/cgi-bin';
  1532.     $DirIcons||='/icon';
  1533.     if ($DNSLookup !~ /[0-2]/)                      { error("DNSLookup parameter is wrong in config/domain file. Value is '$DNSLookup' (should be 0 or 1)"); }
  1534.     if (! $SiteDomain)                              { error("SiteDomain parameter not defined in your config/domain file. You must add it for using this version of AWStats."); }
  1535.     if ($AllowToUpdateStatsFromBrowser !~ /[0-1]/)     { $AllowToUpdateStatsFromBrowser=0; }
  1536.     if ($AllowFullYearView !~ /[0-3]/)                 { $AllowFullYearView=2; }
  1537.     # Optional setup section
  1538.     if ($EnableLockForUpdate !~ /[0-1]/)               { $EnableLockForUpdate=0; }
  1539.     $DNSStaticCacheFile||='dnscache.txt';
  1540.     $DNSLastUpdateCacheFile||='dnscachelastupdate.txt';
  1541.     if ($DNSStaticCacheFile eq $DNSLastUpdateCacheFile)    { error("DNSStaticCacheFile and DNSLastUpdateCacheFile must have different values."); }
  1542.     if ($AllowAccessFromWebToAuthenticatedUsersOnly !~ /[0-1]/)     { $AllowAccessFromWebToAuthenticatedUsersOnly=0; }
  1543.     if ($CreateDirDataIfNotExists !~ /[0-1]/)          { $CreateDirDataIfNotExists=0; }
  1544.     if ($BuildReportFormat !~ /html|xhtml|xml/i)     { $BuildReportFormat='html'; }
  1545.     if ($BuildHistoryFormat !~ /text|xml/)             { $BuildHistoryFormat='text'; }
  1546.     if ($SaveDatabaseFilesWithPermissionsForEveryone !~ /[0-1]/)    { $SaveDatabaseFilesWithPermissionsForEveryone=1; }
  1547.     if ($PurgeLogFile !~ /[0-1]/)                     { $PurgeLogFile=0; }
  1548.     if ($ArchiveLogRecords !~ /[0-1]/)                { $ArchiveLogRecords=0; }
  1549.     if ($KeepBackupOfHistoricFiles !~ /[0-1]/)         { $KeepBackupOfHistoricFiles=0; }
  1550.     $DefaultFile[0]||='index.html';
  1551.     if ($AuthenticatedUsersNotCaseSensitive !~ /[0-1]/)       { $AuthenticatedUsersNotCaseSensitive=0; }
  1552.     if ($URLNotCaseSensitive !~ /[0-1]/)               { $URLNotCaseSensitive=0; }
  1553.     if ($URLWithAnchor !~ /[0-1]/)                     { $URLWithAnchor=0; }
  1554.     $URLQuerySeparators =~ s/\s//g; 
  1555.     if (! $URLQuerySeparators)                         { $URLQuerySeparators='?;'; }
  1556.     if ($URLWithQuery !~ /[0-1]/)                     { $URLWithQuery=0; }
  1557.     if ($URLReferrerWithQuery !~ /[0-1]/)              { $URLReferrerWithQuery=0; }
  1558.     if ($WarningMessages !~ /[0-1]/)                  { $WarningMessages=1; }
  1559.     if ($DebugMessages !~ /[0-1]/)                  { $DebugMessages=1; }
  1560.     if ($NbOfLinesForCorruptedLog !~ /^\d+/ || $NbOfLinesForCorruptedLog<1)    { $NbOfLinesForCorruptedLog=50; }
  1561.     if ($Expires !~ /^\d+/)                         { $Expires=0; }
  1562.     if ($DecodeUA !~ /[0-1]/)                        { $DecodeUA=0; }
  1563.     $MiscTrackerUrl||='/js/awstats_misc_tracker.js';
  1564.     # Optional accuracy setup section
  1565.     if ($LevelForWormsDetection !~ /^\d+/)           { $LevelForWormsDetection=0; }
  1566.     if ($LevelForRobotsDetection !~ /^\d+/)           { $LevelForRobotsDetection=2; }
  1567.     if ($LevelForBrowsersDetection !~ /^\d+/)         { $LevelForBrowsersDetection=2; }
  1568.     if ($LevelForOSDetection !~ /^\d+/)                { $LevelForOSDetection=2; }
  1569.     if ($LevelForRefererAnalyze !~ /^\d+/)            { $LevelForRefererAnalyze=2; }
  1570.     if ($LevelForFileTypesDetection !~ /^\d+/)        { $LevelForFileTypesDetection=2; }
  1571.     if ($LevelForSearchEnginesDetection !~ /^\d+/)    { $LevelForSearchEnginesDetection=2; }
  1572.     if ($LevelForKeywordsDetection !~ /^\d+/)          { $LevelForKeywordsDetection=2; }
  1573.     # Optional extra setup section
  1574.     foreach my $extracpt (1..@ExtraName-1) {
  1575.         if ($ExtraStatTypes[$extracpt] !~ /[PHBL]/)  { $ExtraStatTypes[$extracpt]='PHBL'; }
  1576.         if ($MaxNbOfExtra[$extracpt] !~ /^\d+$/ || $MaxNbOfExtra[$extracpt]<1) { $MaxNbOfExtra[$extracpt]=20; }
  1577.         if ($MinHitExtra[$extracpt] !~ /^\d+$/ || $MinHitExtra[$extracpt]<1) { $MinHitExtra[$extracpt]=1; }
  1578.         if (! $ExtraFirstColumnValues[$extracpt]) { error("Extra section number $extracpt is defined without ExtraSectionFirstColumnValues$extracpt parameter"); }
  1579.         if (! $ExtraFirstColumnFormat[$extracpt]) { $ExtraFirstColumnFormat[$extracpt] = '%s'; }
  1580.     }
  1581.     # Optional appearance setup section
  1582.     if ($MaxRowsInHTMLOutput !~ /^\d+/ || $MaxRowsInHTMLOutput<1)     { $MaxRowsInHTMLOutput=1000; }
  1583.     if ($ShowMenu !~ /[01]/)                         { $ShowMenu=1; }
  1584.     if ($ShowMonthStats !~ /[01UVPHB]/)             { $ShowMonthStats='UVPHB'; }
  1585.     if ($ShowDaysOfMonthStats !~ /[01VPHB]/)        { $ShowDaysOfMonthStats='VPHB'; }
  1586.     if ($ShowDaysOfWeekStats !~ /[01PHBL]/)            { $ShowDaysOfWeekStats='PHBL'; }
  1587.     if ($ShowHoursStats !~ /[01PHBL]/)                 { $ShowHoursStats='PHBL'; }
  1588.     if ($ShowDomainsStats !~ /[01PHB]/)                { $ShowDomainsStats='PHB'; }
  1589.     if ($ShowHostsStats !~ /[01PHBL]/)                 { $ShowHostsStats='PHBL'; }
  1590.     if ($ShowAuthenticatedUsers !~ /[01PHBL]/)         { $ShowAuthenticatedUsers=0; }
  1591.     if ($ShowRobotsStats !~ /[01HBL]/)                { $ShowRobotsStats='HBL'; }
  1592.     if ($ShowWormsStats !~ /[01HBL]/)                { $ShowWormsStats='HBL'; }
  1593.     if ($ShowEMailSenders !~ /[01HBML]/)               { $ShowEMailSenders=0; }
  1594.     if ($ShowEMailReceivers !~ /[01HBML]/)             { $ShowEMailReceivers=0; }
  1595.     if ($ShowSessionsStats !~ /[01]/)                 { $ShowSessionsStats=1; }
  1596.     if ($ShowPagesStats !~ /[01PBEX]/i)               { $ShowPagesStats='PBEX'; }
  1597.     if ($ShowFileTypesStats !~ /[01HBC]/)             { $ShowFileTypesStats='HB'; }
  1598.     if ($ShowFileSizesStats !~ /[01]/)               { $ShowFileSizesStats=1; }
  1599.     if ($ShowOSStats !~ /[01]/)                      { $ShowOSStats=1; }
  1600.     if ($ShowBrowsersStats !~ /[01]/)                { $ShowBrowsersStats=1; }
  1601.     if ($ShowScreenSizeStats !~ /[01]/)               { $ShowScreenSizeStats=0; }
  1602.     if ($ShowOriginStats !~ /[01PH]/)                  { $ShowOriginStats='PH'; }
  1603.     if ($ShowKeyphrasesStats !~ /[01]/)              { $ShowKeyphrasesStats=1; }
  1604.     if ($ShowKeywordsStats !~ /[01]/)                { $ShowKeywordsStats=1; }
  1605.     if ($ShowClusterStats !~ /[01PHB]/)                { $ShowClusterStats=0; }
  1606.     if ($ShowMiscStats !~ /[01ajdfrqwp]/)             { $ShowMiscStats='a'; }
  1607.     if ($ShowHTTPErrorsStats !~ /[01]/)              { $ShowHTTPErrorsStats=1; }
  1608.     if ($ShowSMTPErrorsStats !~ /[01]/)              { $ShowSMTPErrorsStats=0; }
  1609.     if ($AddDataArrayMonthStats !~ /[01]/)            { $AddDataArrayMonthStats=1; }
  1610.     if ($AddDataArrayShowDaysOfMonthStats !~ /[01]/)       { $AddDataArrayShowDaysOfMonthStats=1; }
  1611.     if ($AddDataArrayShowDaysOfWeekStats !~ /[01]/)           { $AddDataArrayShowDaysOfWeekStats=1; }
  1612.     if ($AddDataArrayShowHoursStats !~ /[01]/)              { $AddDataArrayShowHoursStats=1; }
  1613.     my @maxnboflist=('Domain','HostsShown','LoginShown','RobotShown','WormsShown','PageShown','OsShown','BrowsersShown','ScreenSizesShown','RefererShown','KeyphrasesShown','KeywordsShown','EMailsShown');
  1614.     my @maxnboflistdefaultval=(10,10,10,10,5,10,10,10,5,10,10,10,20);
  1615.     foreach my $i (0..(@maxnboflist-1)) {
  1616.         if (! $MaxNbOf{$maxnboflist[$i]} || $MaxNbOf{$maxnboflist[$i]} !~ /^\d+$/ || $MaxNbOf{$maxnboflist[$i]}<1)     { $MaxNbOf{$maxnboflist[$i]}=$maxnboflistdefaultval[$i]; }
  1617.     }
  1618.     my @minhitlist=('Domain','Host','Login','Robot','Worm','File','Os','Browser','ScreenSize','Refer','Keyphrase','Keyword','EMail');
  1619.     my @minhitlistdefaultval=(1,1,1,1,1,1,1,1,1,1,1,1,1);
  1620.     foreach my $i (0..(@minhitlist-1)) {
  1621.         if (! $MinHit{$minhitlist[$i]} || $MinHit{$minhitlist[$i]} !~ /^\d+$/ || $MinHit{$minhitlist[$i]}<1)     { $MinHit{$minhitlist[$i]}=$minhitlistdefaultval[$i]; }
  1622.     }
  1623.     if ($FirstDayOfWeek !~ /[01]/)                   { $FirstDayOfWeek=1; }
  1624.     if ($UseFramesWhenCGI !~ /[01]/)                  { $UseFramesWhenCGI=1; }
  1625.     if ($DetailedReportsOnNewWindows !~ /[012]/)      { $DetailedReportsOnNewWindows=1; }
  1626.     if ($ShowLinksOnUrl !~ /[01]/)                   { $ShowLinksOnUrl=1; }
  1627.     if ($MaxLengthOfShownURL !~ /^\d+/ || $MaxLengthOfShownURL<1) { $MaxLengthOfShownURL=64; }
  1628.     if ($ShowLinksToWhoIs !~ /[01]/)                  { $ShowLinksToWhoIs=0; }
  1629.     $Logo||='awstats_logo6.png';
  1630.     $LogoLink||='http://awstats.sourceforge.net';
  1631.     if ($BarWidth !~ /^\d+/ || $BarWidth<1)         { $BarWidth=260; }
  1632.     if ($BarHeight !~ /^\d+/ || $BarHeight<1)        { $BarHeight=90; }
  1633.     $color_Background =~ s/#//g; if ($color_Background !~ /^[0-9|A-H]+$/i)           { $color_Background='FFFFFF';    }
  1634.     $color_TableBGTitle =~ s/#//g; if ($color_TableBGTitle !~ /^[0-9|A-H]+$/i)       { $color_TableBGTitle='CCCCDD'; }
  1635.     $color_TableTitle =~ s/#//g; if ($color_TableTitle !~ /^[0-9|A-H]+$/i)           { $color_TableTitle='000000'; }
  1636.     $color_TableBG =~ s/#//g; if ($color_TableBG !~ /^[0-9|A-H]+$/i)                 { $color_TableBG='CCCCDD'; }
  1637.     $color_TableRowTitle =~ s/#//g; if ($color_TableRowTitle !~ /^[0-9|A-H]+$/i)     { $color_TableRowTitle='FFFFFF'; }
  1638.     $color_TableBGRowTitle =~ s/#//g; if ($color_TableBGRowTitle !~ /^[0-9|A-H]+$/i) { $color_TableBGRowTitle='ECECEC'; }
  1639.     $color_TableBorder =~ s/#//g; if ($color_TableBorder !~ /^[0-9|A-H]+$/i)         { $color_TableBorder='ECECEC'; }
  1640.     $color_text =~ s/#//g; if ($color_text !~ /^[0-9|A-H]+$/i)                        { $color_text='000000'; }
  1641.     $color_textpercent =~ s/#//g; if ($color_textpercent !~ /^[0-9|A-H]+$/i)           { $color_textpercent='606060'; }
  1642.     $color_titletext =~ s/#//g; if ($color_titletext !~ /^[0-9|A-H]+$/i)              { $color_titletext='000000'; }
  1643.     $color_weekend =~ s/#//g; if ($color_weekend !~ /^[0-9|A-H]+$/i)                  { $color_weekend='EAEAEA'; }
  1644.     $color_link =~ s/#//g; if ($color_link !~ /^[0-9|A-H]+$/i)                        { $color_link='0011BB'; }
  1645.     $color_hover =~ s/#//g; if ($color_hover !~ /^[0-9|A-H]+$/i)                      { $color_hover='605040'; }
  1646.     $color_other =~ s/#//g; if ($color_other !~ /^[0-9|A-H]+$/i)                      { $color_other='666688'; }
  1647.     $color_u =~ s/#//g; if ($color_u !~ /^[0-9|A-H]+$/i)                              { $color_u='FFA060'; }
  1648.     $color_v =~ s/#//g; if ($color_v !~ /^[0-9|A-H]+$/i)                              { $color_v='F4F090'; }
  1649.     $color_p =~ s/#//g; if ($color_p !~ /^[0-9|A-H]+$/i)                              { $color_p='4477DD'; }
  1650.     $color_h =~ s/#//g; if ($color_h !~ /^[0-9|A-H]+$/i)                              { $color_h='66EEFF'; }
  1651.     $color_k =~ s/#//g; if ($color_k !~ /^[0-9|A-H]+$/i)                              { $color_k='2EA495'; }
  1652.     $color_s =~ s/#//g; if ($color_s !~ /^[0-9|A-H]+$/i)                              { $color_s='8888DD'; }
  1653.     $color_e =~ s/#//g; if ($color_e !~ /^[0-9|A-H]+$/i)                              { $color_e='CEC2E8'; }
  1654.     $color_x =~ s/#//g; if ($color_x !~ /^[0-9|A-H]+$/i)                              { $color_x='C1B2E2'; }
  1655.  
  1656.     # Correct param if default value is asked
  1657.     if ($ShowMonthStats eq '1')          { $ShowMonthStats = 'UVPHB'; }
  1658.     if ($ShowDaysOfMonthStats eq '1')     { $ShowDaysOfMonthStats = 'VPHB'; }
  1659.     if ($ShowDaysOfWeekStats eq '1')    { $ShowDaysOfWeekStats = 'PHBL'; }
  1660.     if ($ShowHoursStats eq '1')         { $ShowHoursStats = 'PHBL'; }
  1661.     if ($ShowDomainsStats eq '1')       { $ShowDomainsStats = 'PHB'; }
  1662.     if ($ShowHostsStats eq '1')         { $ShowHostsStats = 'PHBL'; }
  1663.     if ($ShowEMailSenders eq '1')       { $ShowEMailSenders = 'HBML'; }
  1664.     if ($ShowEMailReceivers eq '1')     { $ShowEMailReceivers = 'HBML'; }
  1665.     if ($ShowAuthenticatedUsers eq '1') { $ShowAuthenticatedUsers = 'PHBL'; }
  1666.     if ($ShowRobotsStats eq '1')         { $ShowRobotsStats = 'HBL'; }
  1667.     if ($ShowWormsStats eq '1')         { $ShowWormsStats = 'HBL'; }
  1668.     if ($ShowPagesStats eq '1')         { $ShowPagesStats = 'PBEX'; }
  1669.     if ($ShowFileTypesStats eq '1')     { $ShowFileTypesStats = 'HB'; }
  1670.     if ($ShowOriginStats eq '1')         { $ShowOriginStats = 'PH'; }
  1671.     if ($ShowClusterStats eq '1')         { $ShowClusterStats = 'PHB'; }
  1672.     if ($ShowMiscStats eq '1')             { $ShowMiscStats = 'ajdfrqwp'; }
  1673.  
  1674.     # Convert extra sections data into @ExtraConditionType, @ExtraConditionTypeVal...
  1675.     foreach my $extranum (1..@ExtraName-1) {
  1676.         my $part=0;
  1677.         foreach my $conditioncouple (split(/\s*\|\s*/, $ExtraCondition[$extranum])) {
  1678.              my ($conditiontype, $conditiontypeval)=split(/[,:]/,$conditioncouple,2);
  1679.              $ExtraConditionType[$extranum][$part]=$conditiontype;
  1680.             if ($conditiontypeval =~ /^REGEX\[(.*)\]$/i) { $conditiontypeval=$1; }
  1681.             #else { $conditiontypeval=quotemeta($conditiontypeval); }
  1682.              $ExtraConditionTypeVal[$extranum][$part]=qr/$conditiontypeval/i;
  1683.             $part++;
  1684.          }
  1685.         $part=0;
  1686.         foreach my $rowkeycouple (split(/\s*\|\s*/, $ExtraFirstColumnValues[$extranum])) {
  1687.              my ($rowkeytype, $rowkeytypeval)=split(/[,:]/,$rowkeycouple,2);
  1688.              $ExtraFirstColumnValuesType[$extranum][$part]=$rowkeytype;
  1689.             if ($rowkeytypeval =~ /^REGEX\[(.*)\]$/i) { $rowkeytypeval=$1; }
  1690.             #else { $rowkeytypeval=quotemeta($rowkeytypeval); }
  1691.              $ExtraFirstColumnValuesTypeVal[$extranum][$part]=qr/$rowkeytypeval/i;
  1692.             $part++;
  1693.          }
  1694.     }
  1695.  
  1696.     # Show definitive value for major parameters
  1697.     if ($Debug) {
  1698.         debug(" LogFile='$LogFile'",2);
  1699.         debug(" LogFormat='$LogFormat'",2);
  1700.         debug(" LogSeparator='$LogSeparator'",2);
  1701.         debug(" DNSLookup='$DNSLookup'",2);
  1702.         debug(" DirData='$DirData'",2);
  1703.         debug(" DirCgi='$DirCgi'",2);
  1704.         debug(" DirIcons='$DirIcons'",2);
  1705.         debug(" SiteDomain='$SiteDomain'",2);
  1706.         debug(" MiscTrackerUrl='$MiscTrackerUrl'",2);
  1707.         foreach (keys %MaxNbOf) { debug(" MaxNbOf{$_}=$MaxNbOf{$_}",2); }
  1708.         foreach (keys %MinHit)  { debug(" MinHit{$_}=$MinHit{$_}",2); }
  1709.         foreach my $extranum (1..@ExtraName-1) {
  1710.             debug(" ExtraCodeFilter[$extranum] is array ".join(',',@{$ExtraCodeFilter[$extranum]}),2);
  1711.             debug(" ExtraConditionType[$extranum] is array ".join(',',@{$ExtraConditionType[$extranum]}),2);
  1712.             debug(" ExtraConditionTypeVal[$extranum] is array ".join(',',@{$ExtraConditionTypeVal[$extranum]}),2);
  1713.             debug(" ExtraFirstColumnValuesType[$extranum] is array ".join(',',@{$ExtraFirstColumnValuesType[$extranum]}),2);
  1714.             debug(" ExtraFirstColumnValuesTypeVal[$extranum] is array ".join(',',@{$ExtraFirstColumnValuesTypeVal[$extranum]}),2);
  1715.         }
  1716.     }
  1717.  
  1718.     # Deny URLWithQueryWithOnlyFollowingParameters and URLWithQueryWithoutFollowingParameters both set
  1719.     if (@URLWithQueryWithOnly && @URLWithQueryWithout) {
  1720.         error("URLWithQueryWithOnlyFollowingParameters and URLWithQueryWithoutFollowingParameters can't be both set at the same time");
  1721.     }
  1722.     # Deny $ShowHTTPErrorsStats and $ShowSMTPErrorsStats both set
  1723.     if ($ShowHTTPErrorsStats && $ShowSMTPErrorsStats) {
  1724.         error("ShowHTTPErrorsStats and ShowSMTPErrorsStats can't be both set at the same time");
  1725.     }
  1726.     
  1727.     # Deny LogFile if contains a pipe and PurgeLogFile || ArchiveLogRecords set on
  1728.     if (($PurgeLogFile || $ArchiveLogRecords) && $LogFile =~ /\|\s*$/) {
  1729.         error("A pipe in log file name is not allowed if PurgeLogFile and ArchiveLogRecords are not set to 0");
  1730.     }
  1731.     # If not a migrate, check if DirData is OK
  1732.     if (! $MigrateStats && ! -d $DirData) {
  1733.         if ($CreateDirDataIfNotExists) {
  1734.             if ($Debug) { debug(" Make directory $DirData",2); }
  1735.             my $mkdirok=mkdir "$DirData", 0766;
  1736.             if (! $mkdirok) { error("$PROG failed to create directory DirData (DirData=\"$DirData\", CreateDirDataIfNotExists=$CreateDirDataIfNotExists)."); }
  1737.         }
  1738.         else {
  1739.             error("AWStats database directory defined in config file by 'DirData' parameter ($DirData) does not exist or is not writable.");
  1740.         }
  1741.     }
  1742.  
  1743.     if ($LogType eq 'S') { $NOTSORTEDRECORDTOLERANCE=1000000; }
  1744. }
  1745.  
  1746.  
  1747. #------------------------------------------------------------------------------
  1748. # Function:     Common function used by init function of plugins
  1749. # Parameters:    AWStats version required by plugin
  1750. # Input:        $VERSION
  1751. # Output:        None
  1752. # Return:         '' if ok, "Error: xxx" if error
  1753. #------------------------------------------------------------------------------
  1754. sub Check_Plugin_Version {
  1755.     my $PluginNeedAWStatsVersion=shift;
  1756.     if (! $PluginNeedAWStatsVersion) { return 0; }
  1757.     $VERSION =~ /^(\d+)\.(\d+)/;
  1758.     my $numAWStatsVersion=($1*1000)+$2;
  1759.     $PluginNeedAWStatsVersion =~ /^(\d+)\.(\d+)/;
  1760.     my $numPluginNeedAWStatsVersion=($1*1000)+$2;
  1761.     if     ($numPluginNeedAWStatsVersion > $numAWStatsVersion) {
  1762.         return "Error: AWStats version $PluginNeedAWStatsVersion or higher is required. Detected $VERSION.";
  1763.     }
  1764.     return '';
  1765. }
  1766.  
  1767.  
  1768. #------------------------------------------------------------------------------
  1769. # Function:     Return a checksum for an array of string
  1770. # Parameters:    Array of string
  1771. # Input:        None
  1772. # Output:        None
  1773. # Return:         Checksum number
  1774. #------------------------------------------------------------------------------
  1775. sub CheckSum {
  1776.     my $string=shift;
  1777.     my $checksum=0;
  1778. #    use MD5;
  1779. #     $checksum = MD5->hexhash($string);
  1780.     my $i=0; my $j=0; 
  1781.     while ($i < length($string)) { 
  1782.         my $c=substr($string,$i,1);
  1783.         $checksum+=(ord($c)<<(8*$j));
  1784.         if ($j++ > 3) { $j=0; }
  1785.         $i++;
  1786.     }
  1787.      return $checksum;
  1788. }
  1789.  
  1790.  
  1791. #------------------------------------------------------------------------------
  1792. # Function:     Load plugins files
  1793. # Parameters:    None
  1794. # Input:        $DIR @PluginsToLoad
  1795. # Output:        None
  1796. # Return:         None
  1797. #------------------------------------------------------------------------------
  1798. sub Read_Plugins {
  1799.     # Check plugin files in common possible directories :
  1800.     # Windows and standard package:                "$DIR/plugins" (plugins in same dir than awstats.pl)
  1801.     # Redhat :                                  "/usr/local/awstats/wwwroot/cgi-bin/plugins"
  1802.     # Debian package :                            "/usr/share/awstats/plugins"
  1803.     my @PossiblePluginsDir=("$DIR/plugins","/usr/local/awstats/wwwroot/cgi-bin/plugins","/usr/share/awstats/plugins");
  1804.      my %DirAddedInINC=();
  1805.  
  1806.     foreach my $key (keys %NoLoadPlugin) { if ($NoLoadPlugin{$key} < 0) { push @PluginsToLoad, $key; } }
  1807.     if ($Debug) { debug("Call to Read_Plugins with list: ".join(',',@PluginsToLoad)); }
  1808.     foreach my $plugininfo (@PluginsToLoad) {
  1809.         my @loadplugin=split(/\s+/,$plugininfo,2);
  1810.         my $pluginfile=$loadplugin[0]; $pluginfile =~ s/\.pm$//i;
  1811.         # Check if we plugin is not disabled
  1812.         if ($NoLoadPlugin{$pluginfile} && $NoLoadPlugin{$pluginfile} > 0) {
  1813.             if ($Debug) { debug(" Plugin load for '$pluginfile' has been disabled from parameters"); }
  1814.             next;    
  1815.         }
  1816.         my $pluginparam=$loadplugin[1]||'';
  1817.         $pluginfile =~ /([^\/\\]*)$/;
  1818.         my $pluginname=$1;
  1819.         if ($pluginname) {
  1820.             if (! $PluginsLoaded{'init'}{"$pluginname"}) {        # Plugin not already loaded
  1821.                 my %pluginisfor=('ipv6'=>'u','hashfiles'=>'u','geoip'=>'u','geoipfree'=>'u','timehires'=>'u','timezone'=>'ou',
  1822.                                  'decodeutfkeys'=>'o','hostinfo'=>'o','userinfo'=>'o','urlalias'=>'o','tooltips'=>'o');
  1823.                 if ($pluginisfor{$pluginname}) {
  1824.                     # Do not load "update plugins" if output only
  1825.                     if (! $UpdateStats && scalar keys %HTMLOutput && $pluginisfor{$pluginname} !~ /o/) { $PluginsLoaded{'init'}{"$pluginname"}=1; next; }
  1826.                     # Do not load "output plugins" if update only
  1827.                     if ($UpdateStats && ! scalar keys %HTMLOutput && $pluginisfor{$pluginname} !~ /u/) { $PluginsLoaded{'init'}{"$pluginname"}=1; next; }
  1828.                 }
  1829.                 else { $PluginsLoaded{'init'}{"$pluginname"}=1; }    # Unknown plugins always loaded
  1830.                 # Load plugin
  1831.                 foreach my $dir (@PossiblePluginsDir) {
  1832.                     my $searchdir=$dir;
  1833.                     if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; }
  1834.                     my $pluginpath="${searchdir}${pluginfile}.pm";
  1835.                     if (-s "$pluginpath") {
  1836.                         $PluginDir="${searchdir}";    # Set plugin dir
  1837.                         if ($Debug) { debug(" Try to init plugin '$pluginname' ($pluginpath) with param '$pluginparam'",1); }
  1838.                         if (! $DirAddedInINC{"$dir"}) { 
  1839.                             push @INC, "$dir";
  1840.                             $DirAddedInINC{"$dir"}=1;
  1841.                         }
  1842.                         my $loadret=0;
  1843.                         my $modperl=$ENV{"MOD_PERL"}? eval { require mod_perl; $mod_perl::VERSION >= 1.99 ? 2 : 1 } : 0;
  1844.                         if ($modperl == 2) { $loadret=require "$pluginpath"; }
  1845.                         else { $loadret=require "$pluginfile.pm"; }
  1846.     
  1847.                         if (! $loadret || $loadret =~ /^error/i) {
  1848.                             # Load failed, we stop here
  1849.                             error("Plugin load for plugin '$pluginname' failed with return code: $loadret");
  1850.                         }
  1851.                         my $ret;    # To get init return
  1852.                         my $initfunction="\$ret=Init_$pluginname('$pluginparam')";
  1853.                         my $initret=eval("$initfunction");
  1854.                         if ($initret eq 'xxx') { $initret='Error: The PluginHooksFunctions variable defined in plugin file does not contain list of hooked functions'; }
  1855.                         if (! $initret || $initret =~ /^error/i) {
  1856.                             # Init function failed, we stop here
  1857.                             error("Plugin init for plugin '$pluginname' failed with return code: ".($initret?"$initret":"$@ (A module required by plugin might be missing)."));
  1858.                         }
  1859.                         # Plugin load and init successfull
  1860.                         foreach my $elem (split(/\s+/,$initret)) {
  1861.                             # Some functions can only be plugged once
  1862.                             my @UniquePluginsFunctions=('GetCountryCodeByName','GetCountryCodeByAddr','ChangeTime','GetTimeZoneTitle','GetTime','SearchFile','LoadCache','SaveHash','ShowMenu');
  1863.                             my $isuniquefunc=0;
  1864.                             foreach my $function (@UniquePluginsFunctions) {
  1865.                                 if ("$elem" eq "$function") {
  1866.                                     # We try to load a 'unique' function, so we check and stop if already loaded
  1867.                                     foreach my $otherpluginname (keys %{$PluginsLoaded{"$elem"}})  {
  1868.                                         error("Conflict between plugin '$pluginname' and '$otherpluginname'. They both implements the 'must be unique' function '$elem'.\nYou must choose between one of them. Using together is not possible.");
  1869.                                     }
  1870.                                     $isuniquefunc=1;
  1871.                                     last;
  1872.                                 }
  1873.                             }
  1874.                             if ($isuniquefunc) {
  1875.                                 # TODO Use $PluginsLoaded{"$elem"}="$pluginname"; for unique func
  1876.                                 $PluginsLoaded{"$elem"}{"$pluginname"}=1;
  1877.                             }
  1878.                             else { $PluginsLoaded{"$elem"}{"$pluginname"}=1; }
  1879.                         }
  1880.                         $PluginsLoaded{'init'}{"$pluginname"}=1;
  1881.                         if ($Debug) { debug(" Plugin '$pluginname' now hooks functions '$initret'",1); }
  1882.                         last;
  1883.                     }
  1884.                 }
  1885.                 if (! $PluginsLoaded{'init'}{"$pluginname"}) {
  1886.                     error("Can't open plugin file \"$pluginfile.pm\" for read.\nCheck if file is in \"".($PossiblePluginsDir[0])."\" directory and is readable.");
  1887.                 }
  1888.             }
  1889.             else {
  1890.                 warning("Warning: Tried to load plugin \"$pluginname\" twice. Fix config file.");
  1891.             }
  1892.         }
  1893.         else {
  1894.             error("Plugin \"$pluginfile\" is not a valid plugin name.");
  1895.         }
  1896.     }
  1897.     # In output, geo ip plugins were not loaded, so message changes can't be done in plugin init function
  1898.     if ($PluginsLoaded{'init'}{'geoip'} || $PluginsLoaded{'init'}{'geoipfree'}) { $Message[17]=$Message[25]=$Message[148]; }
  1899. }
  1900.  
  1901. #------------------------------------------------------------------------------
  1902. # Function:        Read history file and create/update tmp history file
  1903. # Parameters:    year,month,withupdate,withpurge,part_to_load[,lastlinenb,lastlineoffset,lastlinechecksum]
  1904. # Input:        $DirData $PROG $FileSuffix $LastLine
  1905. # Output:        None
  1906. # Return:        Tmp history file name created/updated or '' if withupdate is 0
  1907. #------------------------------------------------------------------------------
  1908. sub Read_History_With_TmpUpdate {
  1909.  
  1910.     my $year=sprintf("%04i",shift||0);
  1911.     my $month=sprintf("%02i",shift||0);
  1912.     my $withupdate=shift||0;
  1913.     my $withpurge=shift||0;
  1914.     my $part=shift||'';
  1915.  
  1916.     my $xml=($BuildHistoryFormat eq 'xml'?1:0);
  1917.     my $xmleb='</table><nu>'; my $xmlrb='<tr><td>';
  1918.  
  1919.     my $lastlinenb=shift||0;
  1920.     my $lastlineoffset=shift||0;
  1921.     my $lastlinechecksum=shift||0;
  1922.  
  1923.     my %allsections=('general'=>1,'misc'=>2,'time'=>3,'visitor'=>4,'day'=>5,
  1924.                      'domain'=>6,'cluster'=>7,'login'=>8,'robot'=>9,'worms'=>10,'emailsender'=>11,'emailreceiver'=>12,
  1925.                      'session'=>13,'sider'=>14,'filetypes'=>15,
  1926.                      'os'=>16,'browser'=>17,'screensize'=>18,'unknownreferer'=>19,'unknownrefererbrowser'=>20,
  1927.                      'origin'=>21,'sereferrals'=>22,'pagerefs'=>23,
  1928.                      'searchwords'=>24,'keywords'=>25,
  1929.                      'errors'=>26);
  1930.     my $order=(scalar keys %allsections)+1;
  1931.     foreach (keys %TrapInfosForHTTPErrorCodes) { $allsections{"sider_$_"}=$order++; }
  1932.     foreach (1..@ExtraName-1) { $allsections{"extra_$_"}=$order++; }
  1933.     my $withread=0;
  1934.  
  1935.     # Variable used to read old format history files
  1936.     my $readvisitorforbackward=0;
  1937.  
  1938.     # In standard use of AWStats, the DayRequired variable is always empty
  1939.     if ($DayRequired) { if ($Debug) { debug("Call to Read_History_With_TmpUpdate [$year,$month,withupdate=$withupdate,withpurge=$withpurge,part=$part,lastlinenb=$lastlinenb,lastlineoffset=$lastlineoffset,lastlinechecksum=$lastlinechecksum] ($DayRequired)"); } }
  1940.     else { if ($Debug) { debug("Call to Read_History_With_TmpUpdate [$year,$month,withupdate=$withupdate,withpurge=$withpurge,part=$part,lastlinenb=$lastlinenb,lastlineoffset=$lastlineoffset,lastlinechecksum=$lastlinechecksum]"); } }
  1941.  
  1942.     # Define SectionsToLoad (which sections to load)
  1943.     my %SectionsToLoad = ();
  1944.     if ($part eq 'all') {    # Load all needed sections
  1945.         my $order=1;
  1946.         $SectionsToLoad{'general'}=$order++;
  1947.         # When
  1948.         $SectionsToLoad{'time'}=$order++;    # Always loaded because needed to count TotalPages, TotalHits, TotalBandwidth
  1949.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowHostsStats) || $HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'} || $HTMLOutput{'unknownip'}) { $SectionsToLoad{'visitor'}=$order++; }    # Must be before day, sider and session section
  1950.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && ($ShowDaysOfWeekStats || $ShowDaysOfMonthStats)) || $HTMLOutput{'alldays'}) { $SectionsToLoad{'day'}=$order++; }
  1951.         # Who
  1952.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowDomainsStats) || $HTMLOutput{'alldomains'}) { $SectionsToLoad{'domain'}=$order++; }
  1953.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowAuthenticatedUsers) || $HTMLOutput{'alllogins'} || $HTMLOutput{'lastlogins'}) { $SectionsToLoad{'login'}=$order++; }
  1954.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowRobotsStats) || $HTMLOutput{'allrobots'} || $HTMLOutput{'lastrobots'}) { $SectionsToLoad{'robot'}=$order++; }
  1955.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowWormsStats) || $HTMLOutput{'allworms'} || $HTMLOutput{'lastworms'}) { $SectionsToLoad{'worms'}=$order++; }
  1956.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowEMailSenders) || $HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) { $SectionsToLoad{'emailsender'}=$order++; }
  1957.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowEMailReceivers) || $HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) { $SectionsToLoad{'emailreceiver'}=$order++; }
  1958.         # Navigation
  1959.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowSessionsStats) || $HTMLOutput{'sessions'}) { $SectionsToLoad{'session'}=$order++; }
  1960.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowPagesStats) || $HTMLOutput{'urldetail'} || $HTMLOutput{'urlentry'} || $HTMLOutput{'urlexit'}) { $SectionsToLoad{'sider'}=$order++; }
  1961.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowFileTypesStats) || $HTMLOutput{'filetypes'}) { $SectionsToLoad{'filetypes'}=$order++; }
  1962.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOSStats) || $HTMLOutput{'osdetail'}) { $SectionsToLoad{'os'}=$order++; }
  1963.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowBrowsersStats) || $HTMLOutput{'browserdetail'}) { $SectionsToLoad{'browser'}=$order++; }
  1964.         if ($UpdateStats || $MigrateStats || $HTMLOutput{'unknownos'})      { $SectionsToLoad{'unknownreferer'}=$order++; }
  1965.         if ($UpdateStats || $MigrateStats || $HTMLOutput{'unknownbrowser'}) { $SectionsToLoad{'unknownrefererbrowser'}=$order++; }
  1966.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowScreenSizeStats)) { $SectionsToLoad{'screensize'}=$order++; }
  1967.         # Referers
  1968.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'origin'}) { $SectionsToLoad{'origin'}=$order++; }
  1969.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'refererse'}) { $SectionsToLoad{'sereferrals'}=$order++; }
  1970.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowOriginStats) || $HTMLOutput{'refererpages'}) { $SectionsToLoad{'pagerefs'}=$order++; }
  1971.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowKeyphrasesStats) || $HTMLOutput{'keyphrases'} || $HTMLOutput{'keywords'}) { $SectionsToLoad{'searchwords'}=$order++; }
  1972.         if (! $withupdate && $HTMLOutput{'main'} && $ShowKeywordsStats) { $SectionsToLoad{'keywords'}=$order++; }    # If we update, dont need to load
  1973.         # Others
  1974.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowMiscStats)) { $SectionsToLoad{'misc'}=$order++; }
  1975.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && ($ShowHTTPErrorsStats || $ShowSMTPErrorsStats)) || $HTMLOutput{'errors'}) { $SectionsToLoad{'errors'}=$order++; }
  1976.         foreach (keys %TrapInfosForHTTPErrorCodes) {
  1977.             if ($UpdateStats || $MigrateStats || $HTMLOutput{"errors$_"}) { $SectionsToLoad{"sider_$_"}=$order++; }
  1978.         }
  1979.         if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ShowClusterStats)) { $SectionsToLoad{'cluster'}=$order++; }
  1980.         foreach (1..@ExtraName-1) {
  1981.             if ($UpdateStats || $MigrateStats || ($HTMLOutput{'main'} && $ExtraStatTypes[$_]) || $HTMLOutput{"extra$_"}) { $SectionsToLoad{"extra_$_"}=$order++; }
  1982.         }
  1983.     }
  1984.     else {                    # Load only required sections
  1985.         my $order=1;
  1986.         foreach (split(/\s+/,$part)) { $SectionsToLoad{$_}=$order++; }
  1987.     }
  1988.  
  1989.     # Define SectionsToSave (which sections to save)
  1990.     my %SectionsToSave = ();
  1991.     if ($withupdate) { %SectionsToSave=%allsections; }
  1992.  
  1993.     if ($Debug) {
  1994.         debug(" List of sections marked for load : ".join(' ',(sort { $SectionsToLoad{$a} <=> $SectionsToLoad{$b} } keys %SectionsToLoad)),2);
  1995.         debug(" List of sections marked for save : ".join(' ',(sort { $SectionsToSave{$a} <=> $SectionsToSave{$b} } keys %SectionsToSave)),2);
  1996.     }
  1997.  
  1998.     # Define value for filetowrite and filetoread (Month before Year kept for backward compatibility)
  1999.     my $filetowrite='';
  2000.     my $filetoread='';
  2001.     if ($HistoryAlreadyFlushed{"$year$month"} && -s "$DirData/$PROG$month$year$FileSuffix.tmp.$$") {
  2002.         # tmp history file was already flushed
  2003.         $filetoread="$DirData/$PROG$month$year$FileSuffix.tmp.$$";
  2004.         $filetowrite="$DirData/$PROG$month$year$FileSuffix.tmp.$$.bis";
  2005.     }
  2006.     else {
  2007.         $filetoread="$DirData/$PROG$DayRequired$month$year$FileSuffix.txt";
  2008.         $filetowrite="$DirData/$PROG$month$year$FileSuffix.tmp.$$";
  2009.     }
  2010.     if ($Debug) { debug(" History file to read is '$filetoread'",2); }
  2011.  
  2012.     # Is there an old data file to read or, if migrate, can we open the file for read
  2013.     if (-s $filetoread || $MigrateStats) { $withread=1; }
  2014.  
  2015.     # Open files
  2016.     if ($withread) {
  2017.         open(HISTORY,$filetoread) || error("Couldn't open file \"$filetoread\" for read: $!","","",$MigrateStats);
  2018.         binmode HISTORY;    # Avoid premature EOF due to history files corrupted with \cZ or bin chars
  2019.     }
  2020.     if ($withupdate) {
  2021.         open(HISTORYTMP,">$filetowrite") || error("Couldn't open file \"$filetowrite\" for write: $!");
  2022.         binmode HISTORYTMP;
  2023.         if ($xml) { print HISTORYTMP "<xml>\n\n"; }
  2024.         Save_History("header",$year,$month);
  2025.     }
  2026.  
  2027.     # Loop on read file
  2028.     my $xmlold=0;
  2029.     if ($withread) {
  2030.         my $countlines=0;
  2031.         my $versionnum=0;
  2032.         my @field=();
  2033.         while (<HISTORY>) {
  2034.             chomp $_; s/\r//;
  2035.             $countlines++;
  2036.             
  2037.             # Test if it's xml
  2038.             if (! $xmlold && $_ =~ /^<xml/) {
  2039.                 $xmlold=1;
  2040.                 if ($Debug) { debug(" Data file format is 'xml'",1); }
  2041.                 next;
  2042.             }
  2043.  
  2044.             # Extract version from first line
  2045.             if (! $versionnum && $_ =~ /^AWSTATS DATA FILE (\d+).(\d+)/i) {
  2046.                 $versionnum=($1*1000)+$2;
  2047.                 if ($Debug) { debug(" Data file version is $versionnum",1); }
  2048.                 next;
  2049.             }
  2050.  
  2051.             # Analyze fields
  2052.             @field=split(/\s+/,($xmlold?CleanFromTags($_):$_));
  2053.             if (! $field[0]) { next; }
  2054.  
  2055.             # Here version MUST be defined, or file will be processed as an old data file
  2056.  
  2057.             # BEGIN_GENERAL
  2058.             # TODO Manage GENERAL in a loop like other sections. Need to return error if data file version < 5000 (no END_GENERAL) to say that history files < 5.0 can't be used
  2059.             if ($field[0] eq 'BEGIN_GENERAL')      {
  2060.                 if ($Debug) { debug(" Begin of GENERAL section"); }
  2061.                 next;
  2062.             }
  2063.             if ($field[0] eq 'LastLine' || $field[0] eq "${xmlrb}LastLine")        {
  2064.                 if (! $LastLine || $LastLine < int($field[1])) { $LastLine=int($field[1]); };
  2065.                 if ($field[2]) { $LastLineNumber=int($field[2]); }
  2066.                 if ($field[3]) { $LastLineOffset=int($field[3]); }
  2067.                 if ($field[4]) { $LastLineChecksum=int($field[4]); }
  2068.                 next;
  2069.             }
  2070.             if ($field[0] eq 'FirstTime' || $field[0] eq "${xmlrb}FirstTime")       { if (! $FirstTime{$year.$month} || $FirstTime{$year.$month} > int($field[1])) { $FirstTime{$year.$month}=int($field[1]); }; next; }
  2071.             if ($field[0] eq 'LastTime' || $field[0] eq "${xmlrb}LastTime")        { if (! $LastTime{$year.$month} || $LastTime{$year.$month} < int($field[1])) { $LastTime{$year.$month}=int($field[1]); }; next; }
  2072.             if ($field[0] eq 'LastUpdate' || $field[0] eq "${xmlrb}LastUpdate")      {
  2073.                 if ($LastUpdate < $field[1]) {
  2074.                     $LastUpdate=int($field[1]);
  2075.                     #$LastUpdateLinesRead=int($field[2]);
  2076.                     #$LastUpdateNewLinesRead=int($field[3]);
  2077.                     #$LastUpdateLinesCorrupted=int($field[4]);
  2078.                 };
  2079.                 next;
  2080.             }
  2081.             if ($field[0] eq 'TotalVisits' || $field[0] eq "${xmlrb}TotalVisits")       {
  2082.                 if (! $withupdate) { $MonthVisits{$year.$month}+=int($field[1]); }
  2083.                 # Save in MonthVisits also if migrate from a file < 4.x for backward compatibility
  2084.                 if ($MigrateStats && $versionnum < 4000 && ! $MonthVisits{$year.$month}) {
  2085.                     if ($Debug) { debug("File is version < 4000. We save ".int($field[1])." visits in DayXxx arrays",1); }
  2086.                     $DayHits{$year.$month."00"}+=0;
  2087.                     $DayVisits{$year.$month."00"}+=int($field[1]);
  2088.                 }
  2089.                 next;
  2090.             }
  2091.             if ($field[0] eq 'TotalUnique' || $field[0] eq "${xmlrb}TotalUnique")       { if (! $withupdate) { $MonthUnique{$year.$month}+=int($field[1]); } next; }
  2092.             if ($field[0] eq 'MonthHostsKnown' || $field[0] eq "${xmlrb}MonthHostsKnown")   { if (! $withupdate) { $MonthHostsKnown{$year.$month}+=int($field[1]); } next; }
  2093.             if ($field[0] eq 'MonthHostsUnknown' || $field[0] eq "${xmlrb}MonthHostsUnknown") { if (! $withupdate) { $MonthHostsUnknown{$year.$month}+=int($field[1]); } next; }
  2094.             if (($field[0] eq 'END_GENERAL' || $field[0] eq "${xmleb}END_GENERAL")    # END_GENERAL didn't exist for history files < 5.0
  2095.              || ($versionnum < 5000 && $SectionsToLoad{"general"} && $FirstTime{$year.$month} && $LastTime{$year.$month}) )        {
  2096.                 if ($Debug) { debug(" End of GENERAL section"); }
  2097.                 # Show migrate warning for backward compatibility
  2098.                 if ($versionnum < 5000 && ! $MigrateStats && ! $BadFormatWarning{$year.$month}) {
  2099.                     if ($FrameName ne 'mainleft') {
  2100.                         $BadFormatWarning{$year.$month}=1;
  2101.                         my $message="Warning: Data file '$filetoread' has an old history file format (version $versionnum). You should upgrade it...\nFrom command line: $PROG.$Extension -migrate=\"$filetoread\"";
  2102.                         if ($ENV{'GATEWAY_INTERFACE'} && $AllowToUpdateStatsFromBrowser) { $message.="\nFrom your browser with URL: <a href=\"http://".$ENV{"SERVER_NAME"}.$ENV{"SCRIPT_NAME"}."?migrate=$filetoread\">http://".$ENV{"SERVER_NAME"}.$ENV{"SCRIPT_NAME"}."?migrate=$filetoread</a>"; }
  2103.                         warning("$message");
  2104.                     }
  2105.                 }
  2106.                 if (! ($versionnum < 5000) && $MigrateStats && ! $BadFormatWarning{$year.$month}) {
  2107.                     $BadFormatWarning{$year.$month}=1;
  2108.                     warning("Warning: You are migrating a file that is already a recent version (migrate not required for files version $versionnum).","","",1);
  2109.                 }
  2110.                 # If migrate and version < 4.x we need to include BEGIN_UNKNOWNIP into BEGIN_VISITOR for backward compatibility
  2111.                 if ($MigrateStats && $versionnum < 4000) {
  2112.                     if ($Debug) { debug("File is version < 4000. We add UNKNOWNIP in sections to load",1); }
  2113.                     $SectionsToLoad{'unknownip'}=99;
  2114.                 }
  2115.  
  2116.                 delete $SectionsToLoad{'general'};
  2117.                 if ($SectionsToSave{'general'}) { Save_History('general',$year,$month,$lastlinenb,$lastlineoffset,$lastlinechecksum); delete $SectionsToSave{'general'}; }
  2118.  
  2119.                 # Test for backward compatibility
  2120.                 if ($versionnum < 5000 && ! $withupdate) {
  2121.                     # We must find another way to init MonthUnique MonthHostsKnown and MonthHostsUnknown
  2122.                     if ($Debug) { debug(" We ask to count MonthUnique, MonthHostsKnown and MonthHostsUnknown in visitor section because they are not stored in general section for this data file (version $versionnum)."); }
  2123.                     $readvisitorforbackward=($SectionsToLoad{"visitor"}?1:2);
  2124.                     $SectionsToLoad{"visitor"}=4;
  2125.                 }
  2126.                 else {
  2127.                     if (! scalar %SectionsToLoad) {
  2128.                         if ($Debug) { debug(" Stop reading history file. Got all we need."); }
  2129.                         last;
  2130.                     }
  2131.                 }
  2132.                 if ($versionnum >= 5000) { next; }    # We can forget 'END_GENERAL' line and read next one
  2133.             }
  2134.  
  2135.             # BEGIN_MISC
  2136.             if ($field[0] eq 'BEGIN_MISC')      {
  2137.                 if ($Debug) { debug(" Begin of MISC section"); }
  2138.                 $field[0]='';
  2139.                 my $count=0;my $countloaded=0;
  2140.                 do {
  2141.                     if ($field[0]) {
  2142.                         $count++;
  2143.                         if ($SectionsToLoad{'misc'}) {
  2144.                             $countloaded++;
  2145.                             if ($field[1]) { $_misc_p{$field[0]}+=int($field[1]); }
  2146.                             if ($field[2]) { $_misc_h{$field[0]}+=int($field[2]); }
  2147.                             if ($field[3]) { $_misc_k{$field[0]}+=int($field[3]); }
  2148.                         }
  2149.                     }
  2150.                     $_=<HISTORY>;
  2151.                     chomp $_; s/\r//;
  2152.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2153.                 }
  2154.                 until ($field[0] eq 'END_MISC' || $field[0] eq "${xmleb}END_MISC" || ! $_);
  2155.                 if ($field[0] ne 'END_MISC' && $field[0] ne "${xmleb}END_MISC") { error("History file \"$filetoread\" is corrupted (End of section MISC not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2156.                 if ($Debug) { debug(" End of MISC section ($count entries, $countloaded loaded)"); }
  2157.                 delete $SectionsToLoad{'misc'};
  2158.                 if ($SectionsToSave{'misc'}) {
  2159.                     Save_History('misc',$year,$month); delete $SectionsToSave{'misc'};
  2160.                     if ($withpurge) { %_misc_p=(); %_misc_h=(); %_misc_k=(); }
  2161.                 }
  2162.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2163.                 next;
  2164.             }
  2165.  
  2166.             # BEGIN_CLUSTER
  2167.             if ($field[0] eq 'BEGIN_CLUSTER')      {
  2168.                 if ($Debug) { debug(" Begin of CLUSTER section"); }
  2169.                 $field[0]='';
  2170.                 my $count=0;my $countloaded=0;
  2171.                 do {
  2172.                     if ($field[0]) {
  2173.                         $count++;
  2174.                         if ($SectionsToLoad{'cluster'}) {
  2175.                             $countloaded++;
  2176.                             if ($field[1]) { $_cluster_p{$field[0]}+=int($field[1]); }
  2177.                             if ($field[2]) { $_cluster_h{$field[0]}+=int($field[2]); }
  2178.                             if ($field[3]) { $_cluster_k{$field[0]}+=int($field[3]); }
  2179.                         }
  2180.                     }
  2181.                     $_=<HISTORY>;
  2182.                     chomp $_; s/\r//;
  2183.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2184.                 }
  2185.                 until ($field[0] eq 'END_CLUSTER' || $field[0] eq "${xmleb}END_CLUSTER" || ! $_);
  2186.                 if ($field[0] ne 'END_CLUSTER' && $field[0] ne "${xmleb}END_CLUSTER") { error("History file \"$filetoread\" is corrupted (End of section CLUSTER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2187.                 if ($Debug) { debug(" End of CLUSTER section ($count entries, $countloaded loaded)"); }
  2188.                 delete $SectionsToLoad{'cluster'};
  2189.                 if ($SectionsToSave{'cluster'}) {
  2190.                     Save_History('cluster',$year,$month); delete $SectionsToSave{'cluster'};
  2191.                     if ($withpurge) { %_cluster_p=(); %_cluster_h=(); %_cluster_k=(); }
  2192.                 }
  2193.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2194.                 next;
  2195.             }
  2196.  
  2197.             # BEGIN_TIME
  2198.             if ($field[0] eq 'BEGIN_TIME')      {
  2199.                 my $monthpages=0;my $monthhits=0;my $monthbytes=0;
  2200.                 my $monthnotviewedpages=0;my $monthnotviewedhits=0;my $monthnotviewedbytes=0;
  2201.                 if ($Debug) { debug(" Begin of TIME section"); }
  2202.                 $field[0]='';
  2203.                 my $count=0;my $countloaded=0;
  2204.                 do {
  2205.                     if ($field[0] ne '') {    # Test on ne '' because field[0] is '0' for hour 0)
  2206.                         $count++;
  2207.                         if ($SectionsToLoad{'time'}) {
  2208.                             if ($withupdate || $MonthRequired eq 'all' || $MonthRequired eq "$month") {    # Still required
  2209.                                 $countloaded++;
  2210.                                 if ($field[1]) { $_time_p[$field[0]]+=int($field[1]); }
  2211.                                 if ($field[2]) { $_time_h[$field[0]]+=int($field[2]); }
  2212.                                 if ($field[3]) { $_time_k[$field[0]]+=int($field[3]); }
  2213.                                 if ($field[4]) { $_time_nv_p[$field[0]]+=int($field[4]); }
  2214.                                 if ($field[5]) { $_time_nv_h[$field[0]]+=int($field[5]); }
  2215.                                 if ($field[6]) { $_time_nv_k[$field[0]]+=int($field[6]); }
  2216.                             }
  2217.                             $monthpages+=int($field[1]);
  2218.                             $monthhits+=int($field[2]);
  2219.                             $monthbytes+=int($field[3]);
  2220.                             $monthnotviewedpages+=int($field[4]||0);
  2221.                             $monthnotviewedhits+=int($field[5]||0);
  2222.                             $monthnotviewedbytes+=int($field[6]||0);
  2223.                         }
  2224.                     }
  2225.                     $_=<HISTORY>;
  2226.                     chomp $_; s/\r//;
  2227.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2228.                 }
  2229.                 until ($field[0] eq 'END_TIME' || $field[0] eq "${xmleb}END_TIME" || ! $_);
  2230.                 if ($field[0] ne 'END_TIME' && $field[0] ne "${xmleb}END_TIME") { error("History file \"$filetoread\" is corrupted (End of section TIME not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2231.                 if ($Debug) { debug(" End of TIME section ($count entries, $countloaded loaded)"); }
  2232.                 $MonthPages{$year.$month}+=$monthpages;
  2233.                 $MonthHits{$year.$month}+=$monthhits;
  2234.                 $MonthBytes{$year.$month}+=$monthbytes;
  2235.                 $MonthNotViewedPages{$year.$month}+=$monthnotviewedpages;
  2236.                 $MonthNotViewedHits{$year.$month}+=$monthnotviewedhits;
  2237.                 $MonthNotViewedBytes{$year.$month}+=$monthnotviewedbytes;
  2238.                 delete $SectionsToLoad{'time'};
  2239.                 if ($SectionsToSave{'time'}) {
  2240.                     Save_History('time',$year,$month); delete $SectionsToSave{'time'};
  2241.                     if ($withpurge) { @_time_p=(); @_time_h=(); @_time_k=(); @_time_nv_p=(); @_time_nv_h=(); @_time_nv_k=(); }
  2242.                 }
  2243.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2244.                 next;
  2245.             }
  2246.  
  2247.             # BEGIN_ORIGIN
  2248.             if ($field[0] eq 'BEGIN_ORIGIN')    {
  2249.                 if ($Debug) { debug(" Begin of ORIGIN section"); }
  2250.                 $field[0]='';
  2251.                 my $count=0;my $countloaded=0;
  2252.                 do {
  2253.                     if ($field[0]) {
  2254.                         $count++;
  2255.                         if ($SectionsToLoad{'origin'}) {
  2256.                             if ($field[0] eq 'From0') { $_from_p[0]+=$field[1]; $_from_h[0]+=$field[2]; }
  2257.                             elsif ($field[0] eq 'From1') { $_from_p[1]+=$field[1]; $_from_h[1]+=$field[2]; }
  2258.                             elsif ($field[0] eq 'From2') { $_from_p[2]+=$field[1]; $_from_h[2]+=$field[2]; }
  2259.                             elsif ($field[0] eq 'From3') { $_from_p[3]+=$field[1]; $_from_h[3]+=$field[2]; }
  2260.                             elsif ($field[0] eq 'From4') { $_from_p[4]+=$field[1]; $_from_h[4]+=$field[2]; }
  2261.                             elsif ($field[0] eq 'From5') { $_from_p[5]+=$field[1]; $_from_h[5]+=$field[2]; }
  2262.                         }
  2263.                     }
  2264.                     $_=<HISTORY>;
  2265.                     chomp $_; s/\r//;
  2266.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2267.                 }
  2268.                 until ($field[0] eq 'END_ORIGIN' || $field[0] eq "${xmleb}END_ORIGIN" || ! $_);
  2269.                 if ($field[0] ne 'END_ORIGIN' && $field[0] ne "${xmleb}END_ORIGIN") { error("History file \"$filetoread\" is corrupted (End of section ORIGIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2270.                 if ($Debug) { debug(" End of ORIGIN section ($count entries, $countloaded loaded)"); }
  2271.                 delete $SectionsToLoad{'origin'};
  2272.                 if ($SectionsToSave{'origin'}) {
  2273.                     Save_History('origin',$year,$month); delete $SectionsToSave{'origin'};
  2274.                     if ($withpurge) { @_from_p=(); @_from_h=(); }
  2275.                 }
  2276.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2277.                 next;
  2278.             }
  2279.             # BEGIN_DAY
  2280.             if ($field[0] eq 'BEGIN_DAY')      {
  2281.                 if ($Debug) { debug(" Begin of DAY section"); }
  2282.                 $field[0]='';
  2283.                 my $count=0;my $countloaded=0;
  2284.                 do {
  2285.                     if ($field[0]) {
  2286.                         $count++;
  2287.                         if ($SectionsToLoad{'day'}) {
  2288.                             $countloaded++;
  2289.                             if ($field[1]) { $DayPages{$field[0]}+=int($field[1]); }
  2290.                             $DayHits{$field[0]}+=int($field[2]);                        # DayHits always load (should be >0 and if not it's a day YYYYMM00 resulting of an old file migration)
  2291.                             if ($field[3]) { $DayBytes{$field[0]}+=int($field[3]); }
  2292.                             if ($field[4]) { $DayVisits{$field[0]}+=int($field[4]); }
  2293.                         }
  2294.                     }
  2295.                     $_=<HISTORY>;
  2296.                     chomp $_; s/\r//;
  2297.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2298.                 }
  2299.                 until ($field[0] eq 'END_DAY' || $field[0] eq "${xmleb}END_DAY" || ! $_);
  2300.                 if ($field[0] ne 'END_DAY' && $field[0] ne "${xmleb}END_DAY") { error("History file \"$filetoread\" is corrupted (End of section DAY not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2301.                 if ($Debug) { debug(" End of DAY section ($count entries, $countloaded loaded)"); }
  2302.                 delete $SectionsToLoad{'day'};
  2303.                 # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR
  2304.                 #if ($SectionsToSave{'day'}) {    # Must be made after read of visitor
  2305.                 #    Save_History('day',$year,$month); delete $SectionsToSave{'day'};
  2306.                 #    if ($withpurge) { %DayPages=(); %DayHits=(); %DayBytes=(); %DayVisits=(); }
  2307.                 #}
  2308.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2309.                 next;
  2310.             }
  2311.             # BEGIN_VISITOR
  2312.             if ($field[0] eq 'BEGIN_VISITOR')   {
  2313.                 if ($Debug) { debug(" Begin of VISITOR section"); }
  2314.                 $field[0]='';
  2315.                 my $count=0;my $countloaded=0;
  2316.                 do {
  2317.                     if ($field[0]) {
  2318.                         $count++;
  2319.  
  2320.                         # For backward compatibility
  2321.                         if ($readvisitorforbackward) {
  2322.                             if ($field[1]) { $MonthUnique{$year.$month}++; }
  2323.                             if ($MonthRequired ne 'all') {
  2324.                                 if ($field[0] !~ /^\d+\.\d+\.\d+\.\d+$/ && $field[0] !~ /^[0-9A-F]*:/i) { $MonthHostsKnown{$year.$month}++; }
  2325.                                 else { $MonthHostsUnknown{$year.$month}++; }
  2326.                             }
  2327.                         }
  2328.  
  2329.                         # Process data saved in 'wait' arrays
  2330.                         if ($withupdate && $_waithost_e{$field[0]}){
  2331.                             my $timehostl=int($field[4]||0);
  2332.                             my $timehosts=int($field[5]||0);
  2333.                             my $newtimehosts=($_waithost_s{$field[0]}?$_waithost_s{$field[0]}:$_host_s{$field[0]});
  2334.                             my $newtimehostl=($_waithost_l{$field[0]}?$_waithost_l{$field[0]}:$_host_l{$field[0]});
  2335.                             if ($newtimehosts > $timehostl + $VISITTIMEOUT ) {
  2336.                                 if ($Debug) { debug(" Visit for $field[0] in 'wait' arrays is a new visit different than last in history",4); }
  2337.                                 if ($field[6]) { $_url_x{$field[6]}++; }
  2338.                                 $_url_e{$_waithost_e{$field[0]}}++;
  2339.                                 $newtimehosts =~ /^(\d\d\d\d\d\d\d\d)/; $DayVisits{$1}++;
  2340.                                 if ($timehosts && $timehostl) { $_session{GetSessionRange($timehosts,$timehostl)}++; }
  2341.                                 if ($_waithost_s{$field[0]}) {
  2342.                                     # First session found in log was followed by another one so it's finished
  2343.                                     $_session{GetSessionRange($newtimehosts,$newtimehostl)}++;
  2344.                                 }
  2345.                                 # Here $_host_l $_host_s and $_host_u are correctly defined
  2346.                             }
  2347.                             else {
  2348.                                 if ($Debug) { debug(" Visit for $field[0] in 'wait' arrays is following of last visit in history",4); }
  2349.                                 if ($_waithost_s{$field[0]}) {
  2350.                                     # First session found in log was followed by another one so it's finished
  2351.                                     $_session{GetSessionRange(MinimumButNoZero($timehosts,$newtimehosts),$timehostl>$newtimehostl?$timehostl:$newtimehostl)}++;
  2352.                                     # Here $_host_l $_host_s and $_host_u are correctly defined
  2353.                                 }
  2354.                                 else {
  2355.                                     # We correct $_host_l $_host_s and $_host_u
  2356.                                     if ($timehostl > $newtimehostl) {
  2357.                                         $_host_l{$field[0]}=$timehostl;
  2358.                                         $_host_u{$field[0]}=$field[6];
  2359.                                     }
  2360.                                     if ($timehosts < $newtimehosts) {
  2361.                                         $_host_s{$field[0]}=$timehosts;
  2362.                                     }
  2363.                                 }
  2364.                             }
  2365.                             delete $_waithost_e{$field[0]};
  2366.                             delete $_waithost_l{$field[0]};
  2367.                             delete $_waithost_s{$field[0]};
  2368.                             delete $_waithost_u{$field[0]};
  2369.                         }
  2370.  
  2371.                         # Load records
  2372.                         if ($readvisitorforbackward!=2 && $SectionsToLoad{'visitor'}) { # if readvisitorforbackward==2 we do not load
  2373.                             my $loadrecord=0;
  2374.                             if ($withupdate) {
  2375.                                 $loadrecord=1;
  2376.                             }
  2377.                             else {
  2378.                                 if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) {
  2379.                                     if ((!$FilterIn{'host'} || $field[0] =~ /$FilterIn{'host'}/)
  2380.                                      && (!$FilterEx{'host'} || $field[0] !~ /$FilterEx{'host'}/)) { $loadrecord=1; }
  2381.                                 }
  2382.                                 elsif ($MonthRequired eq 'all' || $field[2] >= $MinHit{'Host'}) {
  2383.                                     if ($HTMLOutput{'unknownip'} && ($field[0] =~ /^\d+\.\d+\.\d+\.\d+$/ || $field[0] =~ /^[0-9A-F]*:/i)) { $loadrecord=1; }
  2384.                                     elsif ($HTMLOutput{'main'} && ($MonthRequired eq 'all' || $countloaded < $MaxNbOf{'HostsShown'})) { $loadrecord=1; }
  2385.                                 }
  2386.                             }
  2387.                             if ($loadrecord) {
  2388.                                 if ($field[1]) { $_host_p{$field[0]}+=$field[1]; }
  2389.                                 if ($field[2]) { $_host_h{$field[0]}+=$field[2]; }
  2390.                                 if ($field[3]) { $_host_k{$field[0]}+=$field[3]; }
  2391.                                 if ($field[4] && ! $_host_l{$field[0]}) {    # We save last connexion params if not previously defined
  2392.                                     $_host_l{$field[0]}=int($field[4]);
  2393.                                     if ($withupdate) {        # field[5] field[6] are used only for update
  2394.                                         if ($field[5] && ! $_host_s{$field[0]}) { $_host_s{$field[0]}=int($field[5]); }
  2395.                                         if ($field[6] && ! $_host_u{$field[0]}) { $_host_u{$field[0]}=$field[6]; }
  2396.                                     }
  2397.                                 }
  2398.                                 $countloaded++;
  2399.                             }
  2400.                         }
  2401.                     }
  2402.                     $_=<HISTORY>;
  2403.                     chomp $_; s/\r//;
  2404.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2405.                 }
  2406.                 until ($field[0] eq 'END_VISITOR' || $field[0] eq "${xmleb}END_VISITOR" || ! $_);
  2407.                 if ($field[0] ne 'END_VISITOR' && $field[0] ne "${xmleb}END_VISITOR") { error("History file \"$filetoread\" is corrupted (End of section VISITOR not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2408.                 if ($Debug) { debug(" End of VISITOR section ($count entries, $countloaded loaded)"); }
  2409.                 delete $SectionsToLoad{'visitor'};
  2410.                 # WE DO NOT SAVE SECTION NOW TO BE SURE TO HAVE THIS LARGE SECTION NOT AT THE BEGINNING OF FILE
  2411.                 #if ($SectionsToSave{'visitor'}) {
  2412.                 #    Save_History('visitor',$year,$month); delete $SectionsToSave{'visitor'};
  2413.                 #    if ($withpurge) { %_host_p=(); %_host_h=(); %_host_k=(); %_host_l=(); %_host_s=(); %_host_u=(); }
  2414.                 #}
  2415.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2416.                 next;
  2417.             }
  2418.             # BEGIN_UNKNOWNIP for backward compatibility
  2419.             if ($field[0] eq 'BEGIN_UNKNOWNIP')   {
  2420.                 my %iptomigrate=();
  2421.                 if ($Debug) { debug(" Begin of UNKNOWNIP section"); }
  2422.                 $field[0]='';
  2423.                 my $count=0;my $countloaded=0;
  2424.                 do {
  2425.                     if ($field[0]) {
  2426.                         $count++;
  2427.                         if ($SectionsToLoad{'unknownip'}) {
  2428.                             $iptomigrate{$field[0]}=$field[1]||0;
  2429.                             $countloaded++;
  2430.                         }
  2431.                     }
  2432.                     $_=<HISTORY>;
  2433.                     chomp $_; s/\r//;
  2434.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2435.                 }
  2436.                 until ($field[0] eq 'END_UNKNOWNIP' || $field[0] eq "${xmleb}END_UNKNOWNIP" || ! $_);
  2437.                 if ($field[0] ne 'END_UNKNOWNIP' && $field[0] ne "${xmleb}END_UNKNOWNIP") { error("History file \"$filetoread\" is corrupted (End of section UNKOWNIP not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2438.                 if ($Debug) { debug(" End of UNKOWNIP section ($count entries, $countloaded loaded)"); }
  2439.                 delete $SectionsToLoad{'visitor'};
  2440.                 # THIS SECTION IS NEVER SAVED. ONLY READ FOR MIGRATE AND CONVERTED INTO VISITOR SECTION
  2441.                 foreach (keys %iptomigrate) {
  2442.                     $_host_p{$_}+=int($_host_p{'Unknown'}/$countloaded);
  2443.                     $_host_h{$_}+=int($_host_h{'Unknown'}/$countloaded);
  2444.                     $_host_k{$_}+=int($_host_k{'Unknown'}/$countloaded);
  2445.                     if ($iptomigrate{$_} > 0) { $_host_l{$_}=$iptomigrate{$_} };
  2446.                 }
  2447.                 delete $_host_p{'Unknown'};
  2448.                 delete $_host_h{'Unknown'};
  2449.                 delete $_host_k{'Unknown'};
  2450.                 delete $_host_l{'Unknown'};
  2451.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2452.                 next;
  2453.             }
  2454.             # BEGIN_LOGIN
  2455.             if ($field[0] eq 'BEGIN_LOGIN')   {
  2456.                 if ($Debug) { debug(" Begin of LOGIN section"); }
  2457.                 $field[0]='';
  2458.                 my $count=0;my $countloaded=0;
  2459.                 do {
  2460.                     if ($field[0]) {
  2461.                         $count++;
  2462.                         if ($SectionsToLoad{'login'}) {
  2463.                             $countloaded++;
  2464.                             if ($field[1]) { $_login_p{$field[0]}+=$field[1]; }
  2465.                             if ($field[2]) { $_login_h{$field[0]}+=$field[2]; }
  2466.                             if ($field[3]) { $_login_k{$field[0]}+=$field[3]; }
  2467.                             if (! $_login_l{$field[0]} && $field[4]) { $_login_l{$field[0]}=int($field[4]); }
  2468.                         }
  2469.                     }
  2470.                     $_=<HISTORY>;
  2471.                     chomp $_; s/\r//;
  2472.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2473.                 }
  2474.                 until ($field[0] eq 'END_LOGIN' || $field[0] eq "${xmleb}END_LOGIN" || ! $_);
  2475.                 if ($field[0] ne 'END_LOGIN' && $field[0] ne "${xmleb}END_LOGIN") { error("History file \"$filetoread\" is corrupted (End of section LOGIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2476.                 if ($Debug) { debug(" End of LOGIN section ($count entries, $countloaded loaded)"); }
  2477.                 delete $SectionsToLoad{'login'};
  2478.                 if ($SectionsToSave{'login'}) {
  2479.                     Save_History('login',$year,$month); delete $SectionsToSave{'login'};
  2480.                     if ($withpurge) { %_login_p=(); %_login_h=(); %_login_k=(); %_login_l=(); }
  2481.                 }
  2482.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2483.                 next;
  2484.             }
  2485.             # BEGIN_DOMAIN
  2486.             if ($field[0] eq 'BEGIN_DOMAIN')   {
  2487.                 if ($Debug) { debug(" Begin of DOMAIN section"); }
  2488.                 $field[0]='';
  2489.                 my $count=0;my $countloaded=0;
  2490.                 do {
  2491.                     if ($field[0]) {
  2492.                         $count++;
  2493.                         if ($SectionsToLoad{'domain'}) {
  2494.                             $countloaded++;
  2495.                             if ($field[1]) { $_domener_p{$field[0]}+=$field[1]; }
  2496.                             if ($field[2]) { $_domener_h{$field[0]}+=$field[2]; }
  2497.                             if ($field[3]) { $_domener_k{$field[0]}+=$field[3]; }
  2498.                         }
  2499.                     }
  2500.                     $_=<HISTORY>;
  2501.                     chomp $_; s/\r//;
  2502.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2503.                 }
  2504.                 until ($field[0] eq 'END_DOMAIN' || $field[0] eq "${xmleb}END_DOMAIN" || ! $_);
  2505.                 if ($field[0] ne 'END_DOMAIN' && $field[0] ne "${xmleb}END_DOMAIN") { error("History file \"$filetoread\" is corrupted (End of section DOMAIN not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2506.                 if ($Debug) { debug(" End of DOMAIN section ($count entries, $countloaded loaded)"); }
  2507.                 delete $SectionsToLoad{'domain'};
  2508.                 if ($SectionsToSave{'domain'}) {
  2509.                     Save_History('domain',$year,$month); delete $SectionsToSave{'domain'};
  2510.                     if ($withpurge) { %_domener_p=(); %_domener_h=(); %_domener_k=(); }
  2511.                 }
  2512.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2513.                 next;
  2514.             }
  2515.             # BEGIN_SESSION
  2516.             if ($field[0] eq 'BEGIN_SESSION')   {
  2517.                 if ($Debug) { debug(" Begin of SESSION section"); }
  2518.                 $field[0]='';
  2519.                 my $count=0;my $countloaded=0;
  2520.                 do {
  2521.                     if ($field[0]) {
  2522.                         $count++;
  2523.                         if ($SectionsToLoad{'session'}) {
  2524.                             $countloaded++;
  2525.                             if ($field[1]) { $_session{$field[0]}+=$field[1]; }
  2526.                         }
  2527.                     }
  2528.                     $_=<HISTORY>;
  2529.                     chomp $_; s/\r//;
  2530.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2531.                 }
  2532.                 until ($field[0] eq 'END_SESSION' || $field[0] eq "${xmleb}END_SESSION" || ! $_);
  2533.                 if ($field[0] ne 'END_SESSION' && $field[0] ne "${xmleb}END_SESSION") { error("History file \"$filetoread\" is corrupted (End of section SESSION not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2534.                 if ($Debug) { debug(" End of SESSION section ($count entries, $countloaded loaded)"); }
  2535.                 delete $SectionsToLoad{'session'};
  2536.                 # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR
  2537.                 #if ($SectionsToSave{'session'}) {
  2538.                 #    Save_History('session',$year,$month); delete $SectionsToSave{'session'}; }
  2539.                 #    if ($withpurge) { %_session=(); }
  2540.                 #}
  2541.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2542.                 next;
  2543.             }
  2544.             # BEGIN_OS
  2545.             if ($field[0] eq 'BEGIN_OS')   {
  2546.                 if ($Debug) { debug(" Begin of OS section"); }
  2547.                 $field[0]='';
  2548.                 my $count=0;my $countloaded=0;
  2549.                 do {
  2550.                     if ($field[0]) {
  2551.                         $count++;
  2552.                         if ($SectionsToLoad{'os'}) {
  2553.                             $countloaded++;
  2554.                             if ($field[1]) { $_os_h{$field[0]}+=$field[1]; }
  2555.                         }
  2556.                     }
  2557.                     $_=<HISTORY>;
  2558.                     chomp $_; s/\r//;
  2559.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2560.                 }
  2561.                 until ($field[0] eq 'END_OS' || $field[0] eq "${xmleb}END_OS" || ! $_);
  2562.                 if ($field[0] ne 'END_OS' && $field[0] ne "${xmleb}END_OS") { error("History file \"$filetoread\" is corrupted (End of section OS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2563.                 if ($Debug) { debug(" End of OS section ($count entries, $countloaded loaded)"); }
  2564.                 delete $SectionsToLoad{'os'};
  2565.                 if ($SectionsToSave{'os'}) {
  2566.                     Save_History('os',$year,$month); delete $SectionsToSave{'os'};
  2567.                     if ($withpurge) { %_os_h=(); }
  2568.                 }
  2569.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2570.                 next;
  2571.             }
  2572.             # BEGIN_BROWSER
  2573.             if ($field[0] eq 'BEGIN_BROWSER')   {
  2574.                 if ($Debug) { debug(" Begin of BROWSER section"); }
  2575.                 $field[0]='';
  2576.                 my $count=0;my $countloaded=0;
  2577.                 do {
  2578.                     if ($field[0]) {
  2579.                         $count++;
  2580.                         if ($SectionsToLoad{'browser'}) {
  2581.                             $countloaded++;
  2582.                             if ($field[1]) { $_browser_h{$field[0]}+=$field[1]; }
  2583.                         }
  2584.                     }
  2585.                     $_=<HISTORY>;
  2586.                     chomp $_; s/\r//;
  2587.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2588.                 }
  2589.                 until ($field[0] eq 'END_BROWSER' || $field[0] eq "${xmleb}END_BROWSER" || ! $_);
  2590.                 if ($field[0] ne 'END_BROWSER' && $field[0] ne "${xmleb}END_BROWSER") { error("History file \"$filetoread\" is corrupted (End of section BROWSER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2591.                 if ($Debug) { debug(" End of BROWSER section ($count entries, $countloaded loaded)"); }
  2592.                 delete $SectionsToLoad{'browser'};
  2593.                 if ($SectionsToSave{'browser'}) {
  2594.                     Save_History('browser',$year,$month); delete $SectionsToSave{'browser'};
  2595.                     if ($withpurge) { %_browser_h=(); }
  2596.                 }
  2597.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2598.                 next;
  2599.             }
  2600.             # BEGIN_UNKNOWNREFERER
  2601.             if ($field[0] eq 'BEGIN_UNKNOWNREFERER')   {
  2602.                 if ($Debug) { debug(" Begin of UNKNOWNREFERER section"); }
  2603.                 $field[0]='';
  2604.                 my $count=0;my $countloaded=0;
  2605.                 do {
  2606.                     if ($field[0]) {
  2607.                         $count++;
  2608.                         if ($SectionsToLoad{'unknownreferer'}) {
  2609.                             $countloaded++;
  2610.                             if (! $_unknownreferer_l{$field[0]}) { $_unknownreferer_l{$field[0]}=int($field[1]); }
  2611.                         }
  2612.                     }
  2613.                     $_=<HISTORY>;
  2614.                     chomp $_; s/\r//;
  2615.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2616.                 }
  2617.                 until ($field[0] eq 'END_UNKNOWNREFERER' || $field[0] eq "${xmleb}END_UNKNOWNREFERER" || ! $_);
  2618.                 if ($field[0] ne 'END_UNKNOWNREFERER' && $field[0] ne "${xmleb}END_UNKNOWNREFERER") { error("History file \"$filetoread\" is corrupted (End of section UNKNOWNREFERER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2619.                 if ($Debug) { debug(" End of UNKNOWNREFERER section ($count entries, $countloaded loaded)"); }
  2620.                 delete $SectionsToLoad{'unknownreferer'};
  2621.                 if ($SectionsToSave{'unknownreferer'}) {
  2622.                     Save_History('unknownreferer',$year,$month); delete $SectionsToSave{'unknownreferer'};
  2623.                     if ($withpurge) { %_unknownreferer_l=(); }
  2624.                 }
  2625.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2626.                 next;
  2627.             }
  2628.             # BEGIN_UNKNOWNREFERERBROWSER
  2629.             if ($field[0] eq 'BEGIN_UNKNOWNREFERERBROWSER')   {
  2630.                 if ($Debug) { debug(" Begin of UNKNOWNREFERERBROWSER section"); }
  2631.                 $field[0]='';
  2632.                 my $count=0;my $countloaded=0;
  2633.                 do {
  2634.                     if ($field[0]) {
  2635.                         $count++;
  2636.                         if ($SectionsToLoad{'unknownrefererbrowser'}) {
  2637.                             $countloaded++;
  2638.                             if (! $_unknownrefererbrowser_l{$field[0]}) { $_unknownrefererbrowser_l{$field[0]}=int($field[1]); }
  2639.                         }
  2640.                     }
  2641.                     $_=<HISTORY>;
  2642.                     chomp $_; s/\r//;
  2643.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2644.                 }
  2645.                 until ($field[0] eq 'END_UNKNOWNREFERERBROWSER' || $field[0] eq "${xmleb}END_UNKNOWNREFERERBROWSER" || ! $_);
  2646.                 if ($field[0] ne 'END_UNKNOWNREFERERBROWSER' && $field[0] ne "${xmleb}END_UNKNOWNREFERERBROWSER") { error("History file \"$filetoread\" is corrupted (End of section UNKNOWNREFERERBROWSER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2647.                 if ($Debug) { debug(" End of UNKNOWNREFERERBROWSER section ($count entries, $countloaded loaded)"); }
  2648.                 delete $SectionsToLoad{'unknownrefererbrowser'};
  2649.                 if ($SectionsToSave{'unknownrefererbrowser'}) {
  2650.                     Save_History('unknownrefererbrowser',$year,$month); delete $SectionsToSave{'unknownrefererbrowser'};
  2651.                     if ($withpurge) { %_unknownrefererbrowser_l=(); }
  2652.                 }
  2653.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2654.                 next;
  2655.             }
  2656.             # BEGIN_SCREENSIZE
  2657.             if ($field[0] eq 'BEGIN_SCREENSIZE')   {
  2658.                 if ($Debug) { debug(" Begin of SCREENSIZE section"); }
  2659.                 $field[0]='';
  2660.                 my $count=0;my $countloaded=0;
  2661.                 do {
  2662.                     if ($field[0]) {
  2663.                         $count++;
  2664.                         if ($SectionsToLoad{'screensize'}) {
  2665.                             $countloaded++;
  2666.                             if ($field[1]) { $_screensize_h{$field[0]}+=$field[1]; }
  2667.                         }
  2668.                     }
  2669.                     $_=<HISTORY>;
  2670.                     chomp $_; s/\r//;
  2671.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2672.                 }
  2673.                 until ($field[0] eq 'END_SCREENSIZE' || $field[0] eq "${xmleb}END_SCREENSIZE" || ! $_);
  2674.                 if ($field[0] ne 'END_SCREENSIZE' && $field[0] ne "${xmleb}END_SCREENSIZE") { error("History file \"$filetoread\" is corrupted (End of section SCREENSIZE not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2675.                 if ($Debug) { debug(" End of SCREENSIZE section ($count entries, $countloaded loaded)"); }
  2676.                 delete $SectionsToLoad{'screensize'};
  2677.                 if ($SectionsToSave{'screensize'}) {
  2678.                     Save_History('screensize',$year,$month); delete $SectionsToSave{'screensize'};
  2679.                     if ($withpurge) { %_screensize_h=(); }
  2680.                 }
  2681.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2682.                 next;
  2683.             }
  2684.             # BEGIN_ROBOT
  2685.             if ($field[0] eq 'BEGIN_ROBOT')   {
  2686.                 if ($Debug) { debug(" Begin of ROBOT section"); }
  2687.                 $field[0]='';
  2688.                 my $count=0;my $countloaded=0;
  2689.                 do {
  2690.                     if ($field[0]) {
  2691.                         $count++;
  2692.                         if ($SectionsToLoad{'robot'}) {
  2693.                             $countloaded++;
  2694.                             if ($field[1]) { $_robot_h{$field[0]}+=$field[1]; }
  2695.                             if ($versionnum < 5000 || ! $field[3]) {        # For backward compatibility
  2696.                                 if (! $_robot_l{$field[0]}) { $_robot_l{$field[0]}=int($field[2]); }
  2697.                             }
  2698.                             else {
  2699.                                 $_robot_k{$field[0]}+=$field[2];
  2700.                                 if (! $_robot_l{$field[0]}) { $_robot_l{$field[0]}=int($field[3]); }
  2701.                             }
  2702.                             if ($field[4]) { $_robot_r{$field[0]}+=$field[4]; }
  2703.                         }
  2704.                     }
  2705.                     $_=<HISTORY>;
  2706.                     chomp $_; s/\r//;
  2707.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2708.                 }
  2709.                 until ($field[0] eq 'END_ROBOT' || $field[0] eq "${xmleb}END_ROBOT" || ! $_);
  2710.                 if ($field[0] ne 'END_ROBOT' && $field[0] ne "${xmleb}END_ROBOT") { error("History file \"$filetoread\" is corrupted (End of section ROBOT not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2711.                 if ($Debug) { debug(" End of ROBOT section ($count entries, $countloaded loaded)"); }
  2712.                 delete $SectionsToLoad{'robot'};
  2713.                 if ($SectionsToSave{'robot'}) {
  2714.                     Save_History('robot',$year,$month); delete $SectionsToSave{'robot'};
  2715.                     if ($withpurge) { %_robot_h=(); %_robot_k=(); %_robot_l=(); %_robot_r=(); }
  2716.                 }
  2717.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2718.                 next;
  2719.             }
  2720.             # BEGIN_WORMS
  2721.             if ($field[0] eq 'BEGIN_WORMS')   {
  2722.                 if ($Debug) { debug(" Begin of WORMS section"); }
  2723.                 $field[0]='';
  2724.                 my $count=0;my $countloaded=0;
  2725.                 do {
  2726.                     if ($field[0]) {
  2727.                         $count++;
  2728.                         if ($SectionsToLoad{'worms'}) {
  2729.                             $countloaded++;
  2730.                             if ($field[1]) { $_worm_h{$field[0]}+=$field[1]; }
  2731.                             $_worm_k{$field[0]}+=$field[2];
  2732.                             if (! $_worm_l{$field[0]}) { $_worm_l{$field[0]}=int($field[3]); }
  2733.                         }
  2734.                     }
  2735.                     $_=<HISTORY>;
  2736.                     chomp $_; s/\r//;
  2737.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2738.                 }
  2739.                 until ($field[0] eq 'END_WORMS' || $field[0] eq "${xmleb}END_WORMS" || ! $_);
  2740.                 if ($field[0] ne 'END_WORMS' && $field[0] ne "${xmleb}END_WORMS") { error("History file \"$filetoread\" is corrupted (End of section WORMS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2741.                 if ($Debug) { debug(" End of WORMS section ($count entries, $countloaded loaded)"); }
  2742.                 delete $SectionsToLoad{'worms'};
  2743.                 if ($SectionsToSave{'worms'}) {
  2744.                     Save_History('worms',$year,$month); delete $SectionsToSave{'worms'};
  2745.                     if ($withpurge) { %_worm_h=(); %_worm_k=(); %_worm_l=(); }
  2746.                 }
  2747.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2748.                 next;
  2749.             }
  2750.             # BEGIN_EMAILS
  2751.             if ($field[0] eq 'BEGIN_EMAILSENDER')   {
  2752.                 if ($Debug) { debug(" Begin of EMAILSENDER section"); }
  2753.                 $field[0]='';
  2754.                 my $count=0;my $countloaded=0;
  2755.                 do {
  2756.                     if ($field[0]) {
  2757.                         $count++;
  2758.                         if ($SectionsToLoad{'emailsender'}) {
  2759.                             $countloaded++;
  2760.                             if ($field[1]) { $_emails_h{$field[0]}+=$field[1]; }
  2761.                             if ($field[2]) { $_emails_k{$field[0]}+=$field[2]; }
  2762.                             if (! $_emails_l{$field[0]}) { $_emails_l{$field[0]}=int($field[3]); }
  2763.                         }
  2764.                     }
  2765.                     $_=<HISTORY>;
  2766.                     chomp $_; s/\r//;
  2767.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2768.                 }
  2769.                 until ($field[0] eq 'END_EMAILSENDER' || $field[0] eq "${xmleb}END_EMAILSENDER" || ! $_);
  2770.                 if ($field[0] ne 'END_EMAILSENDER' && $field[0] ne "${xmleb}END_EMAILSENDER") { error("History file \"$filetoread\" is corrupted (End of section EMAILSENDER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2771.                 if ($Debug) { debug(" End of EMAILSENDER section ($count entries, $countloaded loaded)"); }
  2772.                 delete $SectionsToLoad{'emailsender'};
  2773.                 if ($SectionsToSave{'emailsender'}) {
  2774.                     Save_History('emailsender',$year,$month); delete $SectionsToSave{'emailsender'};
  2775.                     if ($withpurge) { %_emails_h=(); %_emails_k=(); %_emails_l=(); }
  2776.                 }
  2777.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2778.                 next;
  2779.             }
  2780.             # BEGIN_EMAILR
  2781.             if ($field[0] eq 'BEGIN_EMAILRECEIVER')   {
  2782.                 if ($Debug) { debug(" Begin of EMAILRECEIVER section"); }
  2783.                 $field[0]='';
  2784.                 my $count=0;my $countloaded=0;
  2785.                 do {
  2786.                     if ($field[0]) {
  2787.                         $count++;
  2788.                         if ($SectionsToLoad{'emailreceiver'}) {
  2789.                             $countloaded++;
  2790.                             if ($field[1]) { $_emailr_h{$field[0]}+=$field[1]; }
  2791.                             if ($field[2]) { $_emailr_k{$field[0]}+=$field[2]; }
  2792.                             if (! $_emailr_l{$field[0]}) { $_emailr_l{$field[0]}=int($field[3]); }
  2793.                         }
  2794.                     }
  2795.                     $_=<HISTORY>;
  2796.                     chomp $_; s/\r//;
  2797.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2798.                 }
  2799.                 until ($field[0] eq 'END_EMAILRECEIVER' || $field[0] eq "${xmleb}END_EMAILRECEIVER" || ! $_);
  2800.                 if ($field[0] ne 'END_EMAILRECEIVER' && $field[0] ne "${xmleb}END_EMAILRECEIVER") { error("History file \"$filetoread\" is corrupted (End of section EMAILRECEIVER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2801.                 if ($Debug) { debug(" End of EMAILRECEIVER section ($count entries, $countloaded loaded)"); }
  2802.                 delete $SectionsToLoad{'emailreceiver'};
  2803.                 if ($SectionsToSave{'emailreceiver'}) {
  2804.                     Save_History('emailreceiver',$year,$month); delete $SectionsToSave{'emailreceiver'};
  2805.                     if ($withpurge) { %_emailr_h=(); %_emailr_k=(); %_emailr_l=(); }
  2806.                 }
  2807.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2808.                 next;
  2809.             }
  2810.             # BEGIN_SIDER
  2811.             if ($field[0] eq 'BEGIN_SIDER')  {
  2812.                 if ($Debug) { debug(" Begin of SIDER section"); }
  2813.                 $field[0]='';
  2814.                 my $count=0;my $countloaded=0;
  2815.                 do {
  2816.                     if ($field[0]) {
  2817.                         $count++;
  2818.                         if ($SectionsToLoad{'sider'}) {
  2819.                             my $loadrecord=0;
  2820.                             if ($withupdate) {
  2821.                                 $loadrecord=1;
  2822.                             }
  2823.                             else {
  2824.                                 if ($HTMLOutput{'main'}) {
  2825.                                     if ($MonthRequired eq 'all') { $loadrecord=1; }
  2826.                                     else {
  2827.                                         if ($countloaded < $MaxNbOf{'PageShown'} && $field[1] >= $MinHit{'File'}) { $loadrecord=1; }
  2828.                                         $TotalDifferentPages++;
  2829.                                     }
  2830.                                 }
  2831.                                 else {    # This is for $HTMLOutput = urldetail, urlentry or urlexit
  2832.                                     if ($MonthRequired eq 'all' ) {
  2833.                                         if ((!$FilterIn{'url'} || $field[0] =~ /$FilterIn{'url'}/)
  2834.                                          && (!$FilterEx{'url'} || $field[0] !~ /$FilterEx{'url'}/)) { $loadrecord=1; }
  2835.                                     }
  2836.                                     else {
  2837.                                         if ((!$FilterIn{'url'} || $field[0] =~ /$FilterIn{'url'}/)
  2838.                                          && (!$FilterEx{'url'} || $field[0] !~ /$FilterEx{'url'}/)
  2839.                                          && $field[1] >= $MinHit{'File'}) { $loadrecord=1; }
  2840.                                         $TotalDifferentPages++;
  2841.                                     }
  2842.                                 }
  2843.                                 # Posssibilite de mettre if ($FilterIn{'url'} && $field[0] =~ /$FilterIn{'url'}/) mais il faut gerer TotalPages de la meme maniere
  2844.                                 if ($versionnum < 4000) {    # For history files < 4.0
  2845.                                     $TotalEntries+=($field[2]||0);
  2846.                                 }
  2847.                                 else {
  2848.                                     $TotalBytesPages+=($field[2]||0);
  2849.                                     $TotalEntries+=($field[3]||0);
  2850.                                     $TotalExits+=($field[4]||0);
  2851.                                 }
  2852.                             }
  2853.                             if ($loadrecord) {
  2854.                                 if ($field[1]) { $_url_p{$field[0]}+=$field[1]; }
  2855.                                 if ($versionnum < 4000) {    # For history files < 4.0
  2856.                                     if ($field[2]) { $_url_e{$field[0]}+=$field[2]; }
  2857.                                     $_url_k{$field[0]}=0;
  2858.                                 }
  2859.                                 else {
  2860.                                     if ($field[2]) { $_url_k{$field[0]}+=$field[2]; }
  2861.                                     if ($field[3]) { $_url_e{$field[0]}+=$field[3]; }
  2862.                                     if ($field[4]) { $_url_x{$field[0]}+=$field[4]; }
  2863.                                 }
  2864.                                 $countloaded++;
  2865.                             }
  2866.                         }
  2867.                     }
  2868.                     $_=<HISTORY>;
  2869.                     chomp $_; s/\r//;
  2870.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2871.                 }
  2872.                 until ($field[0] eq 'END_SIDER' || $field[0] eq "${xmleb}END_SIDER" || ! $_);
  2873.                 if ($field[0] ne 'END_SIDER' && $field[0] ne "${xmleb}END_SIDER") { error("History file \"$filetoread\" is corrupted (End of section SIDER not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2874.                 if ($Debug) { debug(" End of SIDER section ($count entries, $countloaded loaded)"); }
  2875.                 delete $SectionsToLoad{'sider'};
  2876.                 # WE DO NOT SAVE SECTION NOW BECAUSE VALUES CAN BE CHANGED AFTER READING VISITOR
  2877.                 #if ($SectionsToSave{'sider'}) {
  2878.                 #    Save_History('sider',$year,$month); delete $SectionsToSave{'sider'};
  2879.                 #    if ($withpurge) { %_url_p=(); %_url_k=(); %_url_e=(); %_url_x=(); }
  2880.                 #}
  2881.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2882.                 next;
  2883.             }
  2884.             # BEGIN_FILETYPES
  2885.             if ($field[0] eq 'BEGIN_FILETYPES')   {
  2886.                 if ($Debug) { debug(" Begin of FILETYPES section"); }
  2887.                 $field[0]='';
  2888.                 my $count=0;my $countloaded=0;
  2889.                 do {
  2890.                     if ($field[0]) {
  2891.                         $count++;
  2892.                         if ($SectionsToLoad{'filetypes'}) {
  2893.                             $countloaded++;
  2894.                             if ($field[1]) { $_filetypes_h{$field[0]}+=$field[1]; }
  2895.                             if ($field[2]) { $_filetypes_k{$field[0]}+=$field[2]; }
  2896.                             if ($field[3]) { $_filetypes_gz_in{$field[0]}+=$field[3]; }
  2897.                             if ($field[4]) { $_filetypes_gz_out{$field[0]}+=$field[4]; }
  2898.                         }
  2899.                     }
  2900.                     $_=<HISTORY>;
  2901.                     chomp $_; s/\r//;
  2902.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2903.                 }
  2904.                 until ($field[0] eq 'END_FILETYPES' || $field[0] eq "${xmleb}END_FILETYPES" || ! $_);
  2905.                 if ($field[0] ne 'END_FILETYPES' && $field[0] ne "${xmleb}END_FILETYPES") { error("History file \"$filetoread\" is corrupted (End of section FILETYPES not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2906.                 if ($Debug) { debug(" End of FILETYPES section ($count entries, $countloaded loaded)"); }
  2907.                 delete $SectionsToLoad{'filetypes'};
  2908.                 if ($SectionsToSave{'filetypes'}) {
  2909.                     Save_History('filetypes',$year,$month); delete $SectionsToSave{'filetypes'};
  2910.                     if ($withpurge) { %_filetypes_h=(); %_filetypes_k=(); %_filetypes_gz_in=(); %_filetypes_gz_out=(); }
  2911.                 }
  2912.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2913.                 next;
  2914.             }
  2915.             # BEGIN_SEREFERRALS
  2916.             if ($field[0] eq 'BEGIN_SEREFERRALS')   {
  2917.                 if ($Debug) { debug(" Begin of SEREFERRALS section"); }
  2918.                 $field[0]='';
  2919.                 my $count=0;my $countloaded=0;
  2920.                 do {
  2921.                     if ($field[0]) {
  2922.                         $count++;
  2923.                         if ($SectionsToLoad{'sereferrals'}) {
  2924.                             $countloaded++;
  2925.                             if ($versionnum < 5004) {        # For history files < 5.4
  2926.                                 my $se=$field[0]; $se=~s/\./\\./g;
  2927.                                 if ($SearchEnginesHashID{$se}) {
  2928.                                     $_se_referrals_h{$SearchEnginesHashID{$se}}+=$field[1]||0;
  2929.                                 }
  2930.                                 else {
  2931.                                     $_se_referrals_h{$field[0]}+=$field[1]||0;
  2932.                                 }
  2933.                             }
  2934.                             elsif ($versionnum < 5091) {    # For history files < 5.91
  2935.                                 my $se=$field[0]; $se=~s/\./\\./g;
  2936.                                 if ($SearchEnginesHashID{$se}) {
  2937.                                     $_se_referrals_p{$SearchEnginesHashID{$se}}+=$field[1]||0;
  2938.                                     $_se_referrals_h{$SearchEnginesHashID{$se}}+=$field[2]||0;
  2939.                                 }
  2940.                                 else {
  2941.                                     $_se_referrals_p{$field[0]}+=$field[1]||0;
  2942.                                     $_se_referrals_h{$field[0]}+=$field[2]||0;
  2943.                                 }
  2944.                             } else {
  2945.                                 if ($field[1]) { $_se_referrals_p{$field[0]}+=$field[1]; }
  2946.                                 if ($field[2]) { $_se_referrals_h{$field[0]}+=$field[2]; }
  2947.                             }
  2948.                         }
  2949.                     }
  2950.                     $_=<HISTORY>;
  2951.                     chomp $_; s/\r//;
  2952.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2953.                 }
  2954.                 until ($field[0] eq 'END_SEREFERRALS' || $field[0] eq "${xmleb}END_SEREFERRALS" || ! $_);
  2955.                 if ($field[0] ne 'END_SEREFERRALS' && $field[0] ne "${xmleb}END_SEREFERRALS") { error("History file \"$filetoread\" is corrupted (End of section SEREFERRALS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2956.                 if ($Debug) { debug(" End of SEREFERRALS section ($count entries, $countloaded loaded)"); }
  2957.                 delete $SectionsToLoad{'sereferrals'};
  2958.                 if ($SectionsToSave{'sereferrals'}) {
  2959.                     Save_History('sereferrals',$year,$month); delete $SectionsToSave{'sereferrals'};
  2960.                     if ($withpurge) { %_se_referrals_p=(); %_se_referrals_h=(); }
  2961.                 }
  2962.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  2963.                 next;
  2964.             }
  2965.             # BEGIN_PAGEREFS
  2966.             if ($field[0] eq 'BEGIN_PAGEREFS')   {
  2967.                 if ($Debug) { debug(" Begin of PAGEREFS section"); }
  2968.                 $field[0]='';
  2969.                 my $count=0;my $countloaded=0;
  2970.                 do {
  2971.                     if ($field[0]) {
  2972.                         $count++;
  2973.                         if ($SectionsToLoad{'pagerefs'}) {
  2974.                             my $loadrecord=0;
  2975.                             if ($withupdate) {
  2976.                                 $loadrecord=1;
  2977.                             }
  2978.                             else {
  2979.                                 if ((!$FilterIn{'refererpages'} || $field[0] =~ /$FilterIn{'refererpages'}/)
  2980.                                  && (!$FilterEx{'refererpages'} || $field[0] !~ /$FilterEx{'refererpages'}/)) { $loadrecord=1; }
  2981.                             }
  2982.                             if ($loadrecord) {
  2983.                                 if ($versionnum < 5004) {    # For history files < 5.4
  2984.                                     if ($field[1]) { $_pagesrefs_h{$field[0]}+=int($field[1]); }
  2985.                                 } else {
  2986.                                     if ($field[1]) { $_pagesrefs_p{$field[0]}+=int($field[1]); }
  2987.                                     if ($field[2]) { $_pagesrefs_h{$field[0]}+=int($field[2]); }
  2988.                                 }
  2989.                                 $countloaded++;
  2990.                             }
  2991.                         }
  2992.                     }
  2993.                     $_=<HISTORY>;
  2994.                     chomp $_; s/\r//;
  2995.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  2996.                 }
  2997.                 until ($field[0] eq 'END_PAGEREFS' || $field[0] eq "${xmleb}END_PAGEREFS" || ! $_);
  2998.                 if ($field[0] ne 'END_PAGEREFS' && $field[0] ne "${xmleb}END_PAGEREFS") { error("History file \"$filetoread\" is corrupted (End of section PAGEREFS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  2999.                 if ($Debug) { debug(" End of PAGEREFS section ($count entries, $countloaded loaded)"); }
  3000.                 delete $SectionsToLoad{'pagerefs'};
  3001.                 if ($SectionsToSave{'pagerefs'}) {
  3002.                     Save_History('pagerefs',$year,$month); delete $SectionsToSave{'pagerefs'};
  3003.                     if ($withpurge) { %_pagesrefs_p=(); %_pagesrefs_h=(); }
  3004.                 }
  3005.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3006.                 next;
  3007.             }
  3008.             # BEGIN_SEARCHWORDS
  3009.             if ($field[0] eq 'BEGIN_SEARCHWORDS')   {
  3010.                 if ($Debug) { debug(" Begin of SEARCHWORDS section ($MaxNbOf{'KeyphrasesShown'},$MinHit{'Keyphrase'})"); }
  3011.                 $field[0]='';
  3012.                 my $count=0;my $countloaded=0;
  3013.                 do {
  3014.                     if ($field[0]) {
  3015.                         $count++;
  3016.                         if ($SectionsToLoad{'searchwords'}) {
  3017.                             my $loadrecord=0;
  3018.                             if ($withupdate) {
  3019.                                 $loadrecord=1;
  3020.                             }
  3021.                             else {
  3022.                                 if ($HTMLOutput{'main'}) {
  3023.                                     if ($MonthRequired eq 'all') { $loadrecord=1; }
  3024.                                     else {
  3025.                                         if ($countloaded < $MaxNbOf{'KeyphrasesShown'} && $field[1] >= $MinHit{'Keyphrase'}) { $loadrecord=1; }
  3026.                                         $TotalDifferentKeyphrases++;
  3027.                                         $TotalKeyphrases+=($field[1]||0);
  3028.                                     }
  3029.                                 }
  3030.                                 elsif ($HTMLOutput{'keyphrases'}) {    # Load keyphrases for keyphrases chart
  3031.                                     if ($MonthRequired eq 'all' ) { $loadrecord=1; }
  3032.                                     else {
  3033.                                         if ($field[1] >= $MinHit{'Keyphrase'}) { $loadrecord=1; }
  3034.                                         $TotalDifferentKeyphrases++;
  3035.                                         $TotalKeyphrases+=($field[1]||0);
  3036.                                     }
  3037.                                 }
  3038.                                 if ($HTMLOutput{'keywords'}) {    # Load keyphrases for keywords chart
  3039.                                     $loadrecord=2;
  3040.                                 }
  3041.                             }
  3042.                             if ($loadrecord) {
  3043.                                 if ($field[1]) {
  3044.                                     if ($loadrecord==2) {
  3045.                                         foreach (split(/\+/,$field[0])) {    # field[0] is "val1+val2+..."
  3046.                                             $_keywords{$_}+=$field[1];
  3047.                                         }
  3048.                                     }
  3049.                                     else {
  3050.                                         $_keyphrases{$field[0]}+=$field[1];
  3051.                                     }
  3052.                                 }
  3053.                                 $countloaded++;
  3054.                             }
  3055.                         }
  3056.                     }
  3057.                     $_=<HISTORY>;
  3058.                     chomp $_; s/\r//;
  3059.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  3060.                 }
  3061.                 until ($field[0] eq 'END_SEARCHWORDS' || $field[0] eq "${xmleb}END_SEARCHWORDS" || ! $_);
  3062.                 if ($field[0] ne 'END_SEARCHWORDS' && $field[0] ne "${xmleb}END_SEARCHWORDS") { error("History file \"$filetoread\" is corrupted (End of section SEARCHWORDS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  3063.                 if ($Debug) { debug(" End of SEARCHWORDS section ($count entries, $countloaded loaded)"); }
  3064.                 delete $SectionsToLoad{'searchwords'};
  3065.                 if ($SectionsToSave{'searchwords'}) {
  3066.                     Save_History('searchwords',$year,$month); delete $SectionsToSave{'searchwords'};    # This save searwords and keywords sections
  3067.                     if ($withpurge) { %_keyphrases=(); }
  3068.                 }
  3069.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3070.                 next;
  3071.             }
  3072.             # BEGIN_KEYWORDS
  3073.             if ($field[0] eq 'BEGIN_KEYWORDS')   {
  3074.                 if ($Debug) { debug(" Begin of KEYWORDS section ($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'})"); }
  3075.                 $field[0]='';
  3076.                 my $count=0;my $countloaded=0;
  3077.                 do {
  3078.                     if ($field[0]) {
  3079.                         $count++;
  3080.                         if ($SectionsToLoad{'keywords'}) {
  3081.                             my $loadrecord=0;
  3082.                             if ($MonthRequired eq 'all') { $loadrecord=1; }
  3083.                             else {
  3084.                                 if ($countloaded < $MaxNbOf{'KeywordsShown'} && $field[1] >= $MinHit{'Keyword'}) { $loadrecord=1; }
  3085.                                 $TotalDifferentKeywords++;
  3086.                                 $TotalKeywords+=($field[1]||0);
  3087.                             }
  3088.                             if ($loadrecord) {
  3089.                                 if ($field[1]) { $_keywords{$field[0]}+=$field[1]; }
  3090.                                 $countloaded++;
  3091.                             }
  3092.                         }
  3093.                     }
  3094.                     $_=<HISTORY>;
  3095.                     chomp $_; s/\r//;
  3096.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  3097.                 }
  3098.                 until ($field[0] eq 'END_KEYWORDS' || $field[0] eq "${xmleb}END_KEYWORDS" || ! $_);
  3099.                 if ($field[0] ne 'END_KEYWORDS' && $field[0] ne "${xmleb}END_KEYWORDS") { error("History file \"$filetoread\" is corrupted (End of section KEYWORDS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  3100.                 if ($Debug) { debug(" End of KEYWORDS section ($count entries, $countloaded loaded)"); }
  3101.                 delete $SectionsToLoad{'keywords'};
  3102.                 if ($SectionsToSave{'keywords'}) {
  3103.                     Save_History('keywords',$year,$month); delete $SectionsToSave{'keywords'};
  3104.                     if ($withpurge) { %_keywords=(); }
  3105.                 }
  3106.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3107.                 next;
  3108.             }
  3109.             # BEGIN_ERRORS
  3110.             if ($field[0] eq 'BEGIN_ERRORS')   {
  3111.                 if ($Debug) { debug(" Begin of ERRORS section"); }
  3112.                 $field[0]='';
  3113.                 my $count=0;my $countloaded=0;
  3114.                 do {
  3115.                     if ($field[0]) {
  3116.                         $count++;
  3117.                         if ($SectionsToLoad{'errors'}) {
  3118.                             $countloaded++;
  3119.                             if ($field[1]) { $_errors_h{$field[0]}+=$field[1]; }
  3120.                             if ($field[2]) { $_errors_k{$field[0]}+=$field[2]; }
  3121.                         }
  3122.                     }
  3123.                     $_=<HISTORY>;
  3124.                     chomp $_; s/\r//;
  3125.                     @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  3126.                 }
  3127.                 until ($field[0] eq 'END_ERRORS' || $field[0] eq "${xmleb}END_ERRORS" || ! $_);
  3128.                 if ($field[0] ne 'END_ERRORS' && $field[0] ne "${xmleb}END_ERRORS") { error("History file \"$filetoread\" is corrupted (End of section ERRORS not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  3129.                 if ($Debug) { debug(" End of ERRORS section ($count entries, $countloaded loaded)"); }
  3130.                 delete $SectionsToLoad{'errors'};
  3131.                 if ($SectionsToSave{'errors'}) {
  3132.                     Save_History('errors',$year,$month); delete $SectionsToSave{'errors'};
  3133.                     if ($withpurge) { %_errors_h=(); %_errors_k=(); }
  3134.                 }
  3135.                 if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3136.                 next;
  3137.             }
  3138.             # BEGIN_SIDER_xxx
  3139.             foreach my $code (keys %TrapInfosForHTTPErrorCodes) {
  3140.                 if ($field[0] eq "BEGIN_SIDER_$code")   {
  3141.                     if ($Debug) { debug(" Begin of SIDER_$code section"); }
  3142.                     $field[0]='';
  3143.                     my $count=0;my $countloaded=0;
  3144.                     do {
  3145.                         if ($field[0]) {
  3146.                             $count++;
  3147.                             if ($SectionsToLoad{"sider_$code"}) {
  3148.                                 $countloaded++;
  3149.                                 if ($field[1]) { $_sider404_h{$field[0]}+=$field[1]; }
  3150.                                 if ($withupdate || $HTMLOutput{"errors$code"}) {
  3151.                                     if ($field[2]) { $_referer404_h{$field[0]}=$field[2]; }
  3152.                                 }
  3153.                             }
  3154.                         }
  3155.                         $_=<HISTORY>;
  3156.                         chomp $_; s/\r//;
  3157.                         @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  3158.                     }
  3159.                     until ($field[0] eq "END_SIDER_$code" || $field[0] eq "${xmleb}END_SIDER_$code" || ! $_);
  3160.                     if ($field[0] ne "END_SIDER_$code" && $field[0] ne "${xmleb}END_SIDER_$code") { error("History file \"$filetoread\" is corrupted (End of section SIDER_$code not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  3161.                     if ($Debug) { debug(" End of SIDER_$code section ($count entries, $countloaded loaded)"); }
  3162.                     delete $SectionsToLoad{"sider_$code"};
  3163.                     if ($SectionsToSave{"sider_$code"}) {
  3164.                         Save_History("sider_$code",$year,$month); delete $SectionsToSave{"sider_$code"};
  3165.                         if ($withpurge) { %_sider404_h=(); %_referer404_h=(); }
  3166.                     }
  3167.                     if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3168.                     next;
  3169.                 }
  3170.             }
  3171.             # BEGIN_EXTRA_xxx
  3172.             foreach my $extranum (1..@ExtraName-1) {
  3173.                 if ($field[0] eq "BEGIN_EXTRA_$extranum")   {
  3174.                     if ($Debug) { debug(" Begin of EXTRA_$extranum"); }
  3175.                     $field[0]='';
  3176.                     my $count=0;my $countloaded=0;
  3177.                     do {
  3178.                         if ($field[0] ne '') {
  3179.                             $count++;
  3180.                             if ($SectionsToLoad{"extra_$extranum"}) {
  3181.                                 if ($ExtraStatTypes[$extranum] =~ /P/i && $field[1]) { ${'_section_' . $extranum . '_p'}{$field[0]}+=$field[1]; }
  3182.                                 ${'_section_' . $extranum . '_h'}{$field[0]}+=$field[2];
  3183.                                 if ($ExtraStatTypes[$extranum] =~ /B/i && $field[3]) { ${'_section_' . $extranum . '_k'}{$field[0]}+=$field[3]; }
  3184.                                 if ($ExtraStatTypes[$extranum] =~ /L/i && ! ${'_section_' . $extranum . '_l'}{$field[0]} && $field[4]) { ${'_section_' . $extranum . '_l'}{$field[0]}=int($field[4]); }
  3185.                                 $countloaded++;
  3186.                             }
  3187.                         }
  3188.                         $_=<HISTORY>;
  3189.                         chomp $_; s/\r//;
  3190.                         @field=split(/\s+/,($xmlold?CleanFromTags($_):$_)); $countlines++;
  3191.                     }
  3192.                     until ($field[0] eq "END_EXTRA_$extranum" || $field[0] eq "${xmleb}END_EXTRA_$extranum" || ! $_);
  3193.                     if ($field[0] ne "END_EXTRA_$extranum" && $field[0] ne "${xmleb}END_EXTRA_$extranum") { error("History file \"$filetoread\" is corrupted (End of section EXTRA_$extranum not found).\nRestore a recent backup of this file (data for this month will be restored to backup date), remove it (data for month will be lost), or remove the corrupted section in file (data for at least this section will be lost).","","",1); }
  3194.                     if ($Debug) { debug(" End of EXTRA_$extranum section ($count entries, $countloaded loaded)"); }
  3195.                     delete $SectionsToLoad{"extra_$extranum"};
  3196.                     if ($SectionsToSave{"extra_$extranum"}) {
  3197.                         Save_History("extra_$extranum",$year,$month); delete $SectionsToSave{"extra_$extranum"};
  3198.                         if ($withpurge) { %{'_section_' . $extranum . '_p'}=(); %{'_section_' . $extranum . '_h'}=(); %{'_section_' . $extranum . '_b'}=(); %{'_section_' . $extranum . '_l'}=(); }
  3199.                     }
  3200.                     if (! scalar %SectionsToLoad) { debug(" Stop reading history file. Got all we need."); last; }
  3201.                     next;
  3202.                 }
  3203.             }
  3204.  
  3205.             # For backward compatibility (ORIGIN section was "HitFromx" in old history files)
  3206.             if ($SectionsToLoad{'origin'}) {
  3207.                 if ($field[0] eq 'HitFrom0' ) { $_from_p[0]+=0; $_from_h[0]+=$field[1]; next; }
  3208.                 if ($field[0] eq 'HitFrom1') { $_from_p[1]+=0; $_from_h[1]+=$field[1]; next; }
  3209.                 if ($field[0] eq 'HitFrom2') { $_from_p[2]+=0; $_from_h[2]+=$field[1]; next; }
  3210.                 if ($field[0] eq 'HitFrom3') { $_from_p[3]+=0; $_from_h[3]+=$field[1]; next; }
  3211.                 if ($field[0] eq 'HitFrom4') { $_from_p[4]+=0; $_from_h[4]+=$field[1]; next; }
  3212.                 if ($field[0] eq 'HitFrom5') { $_from_p[5]+=0; $_from_h[5]+=$field[1]; next; }
  3213.             }
  3214.         }
  3215.     }
  3216.  
  3217.     if ($withupdate) {
  3218.         # Process rest of data saved in 'wait' arrays (data for hosts that are not in history file or no history file found)
  3219.         # This can change some values for day, sider and session sections
  3220.         if ($Debug) { debug(" Processing data in 'wait' arrays",3); }
  3221.         foreach (keys %_waithost_e) {
  3222.             if ($Debug) { debug("  Visit in 'wait' array for $_ is a new visit",4); }
  3223.             my $newtimehosts=($_waithost_s{$_}?$_waithost_s{$_}:$_host_s{$_});
  3224.             my $newtimehostl=($_waithost_l{$_}?$_waithost_l{$_}:$_host_l{$_});
  3225.             $_url_e{$_waithost_e{$_}}++;
  3226.             $newtimehosts =~ /^(\d\d\d\d\d\d\d\d)/; $DayVisits{$1}++;
  3227.             if ($_waithost_s{$_}) {
  3228.                 # There was also a second session in processed log
  3229.                 $_session{GetSessionRange($newtimehosts,$newtimehostl)}++;
  3230.             }
  3231.         }
  3232.     }
  3233.  
  3234.     # Write all unwrote sections in section order ('general','time', 'day','sider','session' and other...)
  3235.     foreach my $key (sort { $SectionsToSave{$a} <=> $SectionsToSave{$b} } keys %SectionsToSave) {
  3236.         Save_History("$key",$year,$month,$lastlinenb,$lastlineoffset,$lastlinechecksum);
  3237.     }
  3238.     %SectionsToSave=();
  3239.  
  3240.     # Update offset in map section and last data in general section then close files
  3241.     if ($withupdate) {
  3242.         if ($xml) { print HISTORYTMP "\n\n</xml>\n"; }
  3243.  
  3244.         # Update offset of sections in the MAP section
  3245.         foreach (sort { $PosInFile{$a} <=> $PosInFile{$b} } keys %ValueInFile) {
  3246.             if ($Debug) { debug(" Update offset of section $_=$ValueInFile{$_} in file at offset $PosInFile{$_}"); }
  3247.             if ($PosInFile{"$_"}) {
  3248.                 seek(HISTORYTMP,$PosInFile{"$_"},0); print HISTORYTMP $ValueInFile{"$_"};
  3249.             }
  3250.         }
  3251.         # Save last data in general sections
  3252.         if ($Debug) { debug(" Update MonthVisits=$MonthVisits{$year.$month} in file at offset $PosInFile{TotalVisits}"); }
  3253.         seek(HISTORYTMP,$PosInFile{"TotalVisits"},0); print HISTORYTMP $MonthVisits{$year.$month};
  3254.         if ($Debug) { debug(" Update MonthUnique=$MonthUnique{$year.$month} in file at offset $PosInFile{TotalUnique}"); }
  3255.         seek(HISTORYTMP,$PosInFile{"TotalUnique"},0); print HISTORYTMP $MonthUnique{$year.$month};
  3256.         if ($Debug) { debug(" Update MonthHostsKnown=$MonthHostsKnown{$year.$month} in file at offset $PosInFile{MonthHostsKnown}"); }
  3257.         seek(HISTORYTMP,$PosInFile{"MonthHostsKnown"},0); print HISTORYTMP $MonthHostsKnown{$year.$month};
  3258.         if ($Debug) { debug(" Update MonthHostsUnknown=$MonthHostsUnknown{$year.$month} in file at offset $PosInFile{MonthHostsUnknown}"); }
  3259.         seek(HISTORYTMP,$PosInFile{"MonthHostsUnknown"},0); print HISTORYTMP $MonthHostsUnknown{$year.$month};
  3260.         close(HISTORYTMP) || error("Failed to write temporary history file");
  3261.     }
  3262.     if ($withread) {
  3263.         close(HISTORY) || error("Command for pipe '$filetoread' failed");
  3264.     }
  3265.  
  3266.     # Purge data
  3267.     if ($withpurge) { &Init_HashArray(); }
  3268.  
  3269.     # If update, rename tmp file bis into tmp file or set HistoryAlreadyFlushed
  3270.     if ($withupdate) {
  3271.         if ($HistoryAlreadyFlushed{"$year$month"}) {
  3272.             if (rename($filetowrite,$filetoread)==0) {
  3273.                 error("Failed to update tmp history file $filetoread");
  3274.             }
  3275.         }
  3276.         else {
  3277.             $HistoryAlreadyFlushed{"$year$month"}=1;
  3278.         }
  3279.         if (! $ListOfYears{"$year"} || $ListOfYears{"$year"} lt "$month") { $ListOfYears{"$year"}="$month"; }
  3280.     }
  3281.  
  3282.     # For backward compatibility, if LastLine does not exist, set to LastTime
  3283.     $LastLine||=$LastTime{$year.$month};
  3284.  
  3285.     return ($withupdate?"$filetowrite":"");
  3286. }
  3287.  
  3288. #------------------------------------------------------------------------------
  3289. # Function:        Save a part of history file
  3290. # Parameters:    sectiontosave,year,month[,lastlinenb,lastlineoffset,lastlinechecksum]
  3291. # Input:        $VERSION HISTORYTMP $nowyear $nowmonth $nowday $nowhour $nowmin $nowsec $LastLineNumber $LastLineOffset $LastLineChecksum
  3292. # Output:        None
  3293. # Return:        None
  3294. #------------------------------------------------------------------------------
  3295. sub Save_History {
  3296.     my $sectiontosave=shift||'';
  3297.     my $year=shift||'';
  3298.     my $month=shift||'';
  3299.  
  3300.     my $xml=($BuildHistoryFormat eq 'xml'?1:0);
  3301.     my ($xmlbb,$xmlbs,$xmlbe,$xmlhb,$xmlhs,$xmlhe,$xmlrb,$xmlrs,$xmlre,$xmleb,$xmlee)=();
  3302.     if ($xml) { ($xmlbb,$xmlbs,$xmlbe,$xmlhb,$xmlhs,$xmlhe,$xmlrb,$xmlrs,$xmlre,$xmleb,$xmlee)=("</comment><nu>\n",'</nu><recnb>','</recnb><table>','<tr><th>','</th><th>','</th></tr>','<tr><td>','</td><td>','</td></tr>','</table><nu>',"\n</nu></section>" ); }
  3303.     else { $xmlbs=' '; $xmlhs=' '; $xmlrs=' '; }
  3304.             
  3305.     my $lastlinenb=shift||0;
  3306.     my $lastlineoffset=shift||0;
  3307.     my $lastlinechecksum=shift||0;
  3308.     if (! $lastlinenb) {    # This happens for migrate
  3309.         $lastlinenb=$LastLineNumber;
  3310.         $lastlineoffset=$LastLineOffset;
  3311.         $lastlinechecksum=$LastLineChecksum;
  3312.     }
  3313.     
  3314.     if ($Debug) { debug(" Save_History [sectiontosave=$sectiontosave,year=$year,month=$month,lastlinenb=$lastlinenb,lastlineoffset=$lastlineoffset,lastlinechecksum=$lastlinechecksum]",1); }
  3315.     my $spacebar="                    ";
  3316.     my %keysinkeylist=();
  3317.  
  3318.     # Header
  3319.     if ($sectiontosave eq 'header') {
  3320.         if ($xml) { print HISTORYTMP "<version><lib>\n"; }
  3321.         print HISTORYTMP "AWSTATS DATA FILE $VERSION\n";
  3322.         if ($xml) { print HISTORYTMP "</lib><comment>\n"; }
  3323.         print HISTORYTMP "# If you remove this file, all statistics for date $year-$month will be lost/reset.\n";
  3324.         if ($xml) { print HISTORYTMP "</comment></version>\n"; }
  3325.         print HISTORYTMP "\n";
  3326.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3327.         print HISTORYTMP "# Position (offset in bytes) in this file of beginning of each section for\n";
  3328.         print HISTORYTMP "# direct I/O access. If you made changes somewhere in this file, you should\n";
  3329.         print HISTORYTMP "# also remove completely the MAP section (AWStats will rewrite it at next\n";
  3330.         print HISTORYTMP "# update).\n";
  3331.         print HISTORYTMP "${xmlbb}BEGIN_MAP${xmlbs}".(26+(scalar keys %TrapInfosForHTTPErrorCodes)+(scalar @ExtraName?scalar @ExtraName-1:0))."${xmlbe}\n";
  3332.         print HISTORYTMP "${xmlrb}POS_GENERAL${xmlrs}";$PosInFile{"general"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3333.         # When
  3334.         print HISTORYTMP "${xmlrb}POS_TIME${xmlrs}";$PosInFile{"time"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3335.         print HISTORYTMP "${xmlrb}POS_VISITOR${xmlrs}";$PosInFile{"visitor"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3336.         print HISTORYTMP "${xmlrb}POS_DAY${xmlrs}";$PosInFile{"day"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3337.         # Who
  3338.         print HISTORYTMP "${xmlrb}POS_DOMAIN${xmlrs}";$PosInFile{"domain"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3339.         print HISTORYTMP "${xmlrb}POS_LOGIN${xmlrs}";$PosInFile{"login"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3340.         print HISTORYTMP "${xmlrb}POS_ROBOT${xmlrs}";$PosInFile{"robot"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3341.         print HISTORYTMP "${xmlrb}POS_WORMS${xmlrs}";$PosInFile{"worms"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3342.         print HISTORYTMP "${xmlrb}POS_EMAILSENDER${xmlrs}";$PosInFile{"emailsender"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3343.         print HISTORYTMP "${xmlrb}POS_EMAILRECEIVER${xmlrs}";$PosInFile{"emailreceiver"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3344.         # Navigation
  3345.         print HISTORYTMP "${xmlrb}POS_SESSION${xmlrs}";$PosInFile{"session"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3346.         print HISTORYTMP "${xmlrb}POS_SIDER${xmlrs}";$PosInFile{"sider"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3347.         print HISTORYTMP "${xmlrb}POS_FILETYPES${xmlrs}";$PosInFile{"filetypes"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3348.         print HISTORYTMP "${xmlrb}POS_OS${xmlrs}";$PosInFile{"os"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3349.         print HISTORYTMP "${xmlrb}POS_BROWSER${xmlrs}";$PosInFile{"browser"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3350.         print HISTORYTMP "${xmlrb}POS_SCREENSIZE${xmlrs}";$PosInFile{"screensize"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3351.         print HISTORYTMP "${xmlrb}POS_UNKNOWNREFERER${xmlrs}";$PosInFile{'unknownreferer'}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3352.         print HISTORYTMP "${xmlrb}POS_UNKNOWNREFERERBROWSER${xmlrs}";$PosInFile{'unknownrefererbrowser'}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3353.         # Referers
  3354.         print HISTORYTMP "${xmlrb}POS_ORIGIN${xmlrs}";$PosInFile{"origin"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3355.         print HISTORYTMP "${xmlrb}POS_SEREFERRALS${xmlrs}";$PosInFile{"sereferrals"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3356.         print HISTORYTMP "${xmlrb}POS_PAGEREFS${xmlrs}";$PosInFile{"pagerefs"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3357.         print HISTORYTMP "${xmlrb}POS_SEARCHWORDS${xmlrs}";$PosInFile{"searchwords"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3358.         print HISTORYTMP "${xmlrb}POS_KEYWORDS${xmlrs}";$PosInFile{"keywords"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3359.         # Others
  3360.         print HISTORYTMP "${xmlrb}POS_MISC${xmlrs}";$PosInFile{"misc"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3361.         print HISTORYTMP "${xmlrb}POS_ERRORS${xmlrs}";$PosInFile{"errors"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3362.         print HISTORYTMP "${xmlrb}POS_CLUSTER${xmlrs}";$PosInFile{"cluster"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3363.         foreach (keys %TrapInfosForHTTPErrorCodes) {
  3364.             print HISTORYTMP "${xmlrb}POS_SIDER_$_${xmlrs}";$PosInFile{"sider_$_"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3365.         }
  3366.         foreach (1..@ExtraName-1) {
  3367.             print HISTORYTMP "${xmlrb}POS_EXTRA_$_${xmlrs}";$PosInFile{"extra_$_"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3368.         }
  3369.         print HISTORYTMP "${xmleb}END_MAP${xmlee}\n";
  3370.     }
  3371.  
  3372.     # General
  3373.     if ($sectiontosave eq 'general') {
  3374.         if ($LastUpdate < int("$nowyear$nowmonth$nowday$nowhour$nowmin$nowsec")) { $LastUpdate=int("$nowyear$nowmonth$nowday$nowhour$nowmin$nowsec"); }
  3375.         print HISTORYTMP "\n";
  3376.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3377.         print HISTORYTMP "# LastLine    = Date of last record processed - Last record line number in last log - Last record offset in last log - Last record signature value\n";
  3378.         print HISTORYTMP "# FirstTime   = Date of first visit for history file\n";
  3379.         print HISTORYTMP "# LastTime    = Date of last visit for history file\n";
  3380.         print HISTORYTMP "# LastUpdate  = Date of last update - Nb of parsed records - Nb of parsed old records - Nb of parsed new records - Nb of parsed corrupted - Nb of parsed dropped\n";
  3381.         print HISTORYTMP "# TotalVisits = Number of visits\n";
  3382.         print HISTORYTMP "# TotalUnique = Number of unique visitors\n";
  3383.         print HISTORYTMP "# MonthHostsKnown   = Number of hosts known\n";
  3384.         print HISTORYTMP "# MonthHostsUnKnown = Number of hosts unknown\n";
  3385.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3386.         print HISTORYTMP "${xmlbb}BEGIN_GENERAL${xmlbs}8${xmlbe}\n";
  3387.         print HISTORYTMP "${xmlrb}LastLine${xmlrs}".($LastLine>0?$LastLine:$LastTime{$year.$month})." $lastlinenb $lastlineoffset $lastlinechecksum${xmlre}\n";
  3388.         print HISTORYTMP "${xmlrb}FirstTime${xmlrs}$FirstTime{$year.$month}${xmlre}\n";
  3389.         print HISTORYTMP "${xmlrb}LastTime${xmlrs}$LastTime{$year.$month}${xmlre}\n";
  3390.         print HISTORYTMP "${xmlrb}LastUpdate${xmlrs}$LastUpdate $NbOfLinesParsed $NbOfOldLines $NbOfNewLines $NbOfLinesCorrupted $NbOfLinesDropped${xmlre}\n";
  3391.         print HISTORYTMP "${xmlrb}TotalVisits${xmlrs}";$PosInFile{"TotalVisits"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3392.         print HISTORYTMP "${xmlrb}TotalUnique${xmlrs}";$PosInFile{"TotalUnique"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3393.         print HISTORYTMP "${xmlrb}MonthHostsKnown${xmlrs}";$PosInFile{"MonthHostsKnown"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3394.         print HISTORYTMP "${xmlrb}MonthHostsUnknown${xmlrs}";$PosInFile{"MonthHostsUnknown"}=tell HISTORYTMP;print HISTORYTMP "$spacebar${xmlre}\n";
  3395.         print HISTORYTMP "${xmleb}".(${xmleb}?"\n":"")."END_GENERAL${xmlee}\n";    # END_GENERAL on a new line following xml tag because END_ detection does not work like other sections
  3396.     }
  3397.  
  3398.     # When
  3399.     if ($sectiontosave eq 'time') {
  3400.         print HISTORYTMP "\n";
  3401.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3402.         print HISTORYTMP "# Hour - Pages - Hits - Bandwidth - Not viewed Pages - Not viewed Hits - Not viewed Bandwidth\n";
  3403.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3404.         print HISTORYTMP "${xmlbb}BEGIN_TIME${xmlbs}24${xmlbe}\n";
  3405.         for (my $ix=0; $ix<=23; $ix++) { print HISTORYTMP "${xmlrb}$ix${xmlrs}".int($_time_p[$ix])."${xmlrs}".int($_time_h[$ix])."${xmlrs}".int($_time_k[$ix])."${xmlrs}".int($_time_nv_p[$ix])."${xmlrs}".int($_time_nv_h[$ix])."${xmlrs}".int($_time_nv_k[$ix])."${xmlre}\n"; }
  3406.         print HISTORYTMP "${xmleb}END_TIME${xmlee}\n";
  3407.     }
  3408.     if ($sectiontosave eq 'day') {    # This section must be saved after VISITOR section is read
  3409.         print HISTORYTMP "\n";
  3410.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3411.         print HISTORYTMP "# Date - Pages - Hits - Bandwidth - Visits\n";
  3412.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3413.         print HISTORYTMP "${xmlbb}BEGIN_DAY${xmlbs}".(scalar keys %DayHits)."${xmlbe}\n";
  3414.         my $monthvisits=0;
  3415.         foreach (sort keys %DayHits) {
  3416.             if ($_ =~ /^$year$month/i) {    # Found a day entry of the good month
  3417.                 my $page=$DayPages{$_}||0;
  3418.                 my $hits=$DayHits{$_}||0;
  3419.                 my $bytes=$DayBytes{$_}||0;
  3420.                 my $visits=$DayVisits{$_}||0;
  3421.                 print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$hits${xmlrs}$bytes${xmlrs}$visits${xmlre}\n";
  3422.                 $monthvisits+=$visits;
  3423.             }
  3424.         }
  3425.         $MonthVisits{$year.$month}=$monthvisits;
  3426.         print HISTORYTMP "${xmleb}END_DAY${xmlee}\n";
  3427.     }
  3428.  
  3429.     # Who
  3430.     if ($sectiontosave eq 'domain') {
  3431.         print HISTORYTMP "\n";
  3432.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'Domain'}</sortfor><comment>\n"; }
  3433.         print HISTORYTMP "# Domain - Pages - Hits - Bandwidth\n";
  3434.         print HISTORYTMP "# The $MaxNbOf{'Domain'} first Pages must be first (order not required for others)\n";
  3435.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3436.         print HISTORYTMP "${xmlbb}BEGIN_DOMAIN${xmlbs}".(scalar keys %_domener_h)."${xmlbe}\n";
  3437.         # We save page list in score sorted order to get a -output faster and with less use of memory.
  3438.         &BuildKeyList($MaxNbOf{'Domain'},$MinHit{'Domain'},\%_domener_h,\%_domener_p);
  3439.         my %keysinkeylist=();
  3440.         foreach (@keylist) {
  3441.             $keysinkeylist{$_}=1;
  3442.             my $page=$_domener_p{$_}||0;
  3443.             my $bytes=$_domener_k{$_}||0;        # ||0 could be commented to reduce history file size
  3444.             print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$_domener_h{$_}${xmlrs}$bytes${xmlre}\n";
  3445.         }
  3446.         foreach (keys %_domener_h) {
  3447.             if ($keysinkeylist{$_}) { next; }
  3448.             my $page=$_domener_p{$_}||0;
  3449.             my $bytes=$_domener_k{$_}||0;        # ||0 could be commented to reduce history file size
  3450.             print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}$_domener_h{$_}${xmlrs}$bytes${xmlre}\n";
  3451.         }
  3452.         print HISTORYTMP "${xmleb}END_DOMAIN${xmlee}\n";
  3453.     }
  3454.     if ($sectiontosave eq 'visitor') {
  3455.         print HISTORYTMP "\n";
  3456.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'HostsShown'}</sortfor><comment>\n"; }
  3457.         print HISTORYTMP "# Host - Pages - Hits - Bandwidth - Last visit date - [Start date of last visit] - [Last page of last visit]\n";
  3458.         print HISTORYTMP "# [Start date of last visit] and [Last page of last visit] are saved only if session is not finished\n";
  3459.         print HISTORYTMP "# The $MaxNbOf{'HostsShown'} first Hits must be first (order not required for others)\n";
  3460.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3461.         print HISTORYTMP "${xmlbb}BEGIN_VISITOR${xmlbs}".(scalar keys %_host_h)."${xmlbe}\n";
  3462.         my $monthhostsknown=0;
  3463.         # We save page list in score sorted order to get a -output faster and with less use of memory.
  3464.         &BuildKeyList($MaxNbOf{'HostsShown'},$MinHit{'Host'},\%_host_h,\%_host_p);
  3465.         my %keysinkeylist=();
  3466.         foreach my $key (@keylist) {
  3467.             if ($key !~ /^\d+\.\d+\.\d+\.\d+$/ &&  $key !~ /^[0-9A-F]*:/i) { $monthhostsknown++; }
  3468.             $keysinkeylist{$key}=1;
  3469.             my $page=$_host_p{$key}||0;
  3470.             my $bytes=$_host_k{$key}||0;
  3471.             my $timehostl=$_host_l{$key}||0;
  3472.             my $timehosts=$_host_s{$key}||0;
  3473.             my $lastpage=$_host_u{$key}||'';
  3474.             if ($timehostl && $timehosts && $lastpage) {
  3475.                 if (($timehostl+$VISITTIMEOUT) < $LastLine) {
  3476.                     # Session for this user is expired
  3477.                     if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; }
  3478.                     if ($lastpage) { $_url_x{$lastpage}++; }
  3479.                     delete $_host_s{$key};
  3480.                     delete $_host_u{$key};
  3481.                     print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlre}\n";
  3482.                 }
  3483.                 else {
  3484.                     # If this user has started a new session that is not expired
  3485.                     print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlrs}$timehosts${xmlrs}$lastpage${xmlre}\n";
  3486.                 }
  3487.             }
  3488.             else {
  3489.                 my $hostl=$timehostl||'';
  3490.                 print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$hostl${xmlre}\n";
  3491.             }
  3492.         }
  3493.         foreach my $key (keys %_host_h) {
  3494.             if ($keysinkeylist{$key}) { next; }
  3495.             if ($key !~ /^\d+\.\d+\.\d+\.\d+$/ && $key !~ /^[0-9A-F]*:/i) { $monthhostsknown++; }
  3496.             my $page=$_host_p{$key}||0;
  3497.             my $bytes=$_host_k{$key}||0;
  3498.             my $timehostl=$_host_l{$key}||0;
  3499.             my $timehosts=$_host_s{$key}||0;
  3500.             my $lastpage=$_host_u{$key}||'';
  3501.             if ($timehostl && $timehosts && $lastpage) {
  3502.                 if (($timehostl+$VISITTIMEOUT) < $LastLine) {
  3503.                     # Session for this user is expired
  3504.                     if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; }
  3505.                     if ($lastpage) { $_url_x{$lastpage}++; }
  3506.                     delete $_host_s{$key};
  3507.                     delete $_host_u{$key};
  3508.                     print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlre}\n";
  3509.                 }
  3510.                 else {
  3511.                     # If this user has started a new session that is not expired
  3512.                     print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$timehostl${xmlrs}$timehosts${xmlrs}$lastpage${xmlre}\n";
  3513.                 }
  3514.             }
  3515.             else {
  3516.                 my $hostl=$timehostl||'';
  3517.                 print HISTORYTMP "${xmlrb}$key${xmlrs}$page${xmlrs}$_host_h{$key}${xmlrs}$bytes${xmlrs}$hostl${xmlre}\n";
  3518.             }
  3519.         }
  3520.         $MonthUnique{$year.$month}=(scalar keys %_host_p);
  3521.         $MonthHostsKnown{$year.$month}=$monthhostsknown;
  3522.         $MonthHostsUnknown{$year.$month}=(scalar keys %_host_h) - $monthhostsknown;
  3523.         print HISTORYTMP "${xmleb}END_VISITOR${xmlee}\n";
  3524.     }
  3525.     if ($sectiontosave eq 'login') {
  3526.         print HISTORYTMP "\n";
  3527.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'LoginShown'}</sortfor><comment>\n"; }
  3528.         print HISTORYTMP "# Login - Pages - Hits - Bandwidth - Last visit\n";
  3529.         print HISTORYTMP "# The $MaxNbOf{'LoginShown'} first Pages must be first (order not required for others)\n";
  3530.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3531.         print HISTORYTMP "${xmlbb}BEGIN_LOGIN${xmlbs}".(scalar keys %_login_h)."${xmlbe}\n";
  3532.         # We save login list in score sorted order to get a -output faster and with less use of memory.
  3533.         &BuildKeyList($MaxNbOf{'LoginShown'},$MinHit{'Login'},\%_login_h,\%_login_p);
  3534.         my %keysinkeylist=();
  3535.         foreach (@keylist) {
  3536.             $keysinkeylist{$_}=1;
  3537.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_login_p{$_}||0)."${xmlrs}".int($_login_h{$_}||0)."${xmlrs}".int($_login_k{$_}||0)."${xmlrs}".($_login_l{$_}||'')."${xmlre}\n";
  3538.         }
  3539.         foreach (keys %_login_h) {
  3540.             if ($keysinkeylist{$_}) { next; }
  3541.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_login_p{$_}||0)."${xmlrs}".int($_login_h{$_}||0)."${xmlrs}".int($_login_k{$_}||0)."${xmlrs}".($_login_l{$_}||'')."${xmlre}\n";
  3542.         }
  3543.         print HISTORYTMP "${xmleb}END_LOGIN${xmlee}\n";
  3544.     }
  3545.     if ($sectiontosave eq 'robot') {
  3546.         print HISTORYTMP "\n";
  3547.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'RobotShown'}</sortfor><comment>\n"; }
  3548.         print HISTORYTMP "# Robot ID - Hits - Bandwidth - Last visit - Hits on robots.txt\n";
  3549.         print HISTORYTMP "# The $MaxNbOf{'RobotShown'} first Hits must be first (order not required for others)\n";
  3550.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3551.         print HISTORYTMP "${xmlbb}BEGIN_ROBOT${xmlbs}".(scalar keys %_robot_h)."${xmlbe}\n";
  3552.         # We save robot list in score sorted order to get a -output faster and with less use of memory.
  3553.         &BuildKeyList($MaxNbOf{'RobotShown'},$MinHit{'Robot'},\%_robot_h,\%_robot_h);
  3554.         my %keysinkeylist=();
  3555.         foreach (@keylist) {
  3556.             $keysinkeylist{$_}=1;
  3557.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_robot_h{$_})."${xmlrs}".int($_robot_k{$_})."${xmlrs}$_robot_l{$_}${xmlrs}".int($_robot_r{$_})."${xmlre}\n";
  3558.         }
  3559.         foreach (keys %_robot_h) {
  3560.             if ($keysinkeylist{$_}) { next; }
  3561.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_robot_h{$_})."${xmlrs}".int($_robot_k{$_})."${xmlrs}$_robot_l{$_}${xmlrs}".int($_robot_r{$_})."${xmlre}\n";
  3562.         }
  3563.         print HISTORYTMP "${xmleb}END_ROBOT${xmlee}\n";
  3564.     }
  3565.     if ($sectiontosave eq 'worms') {
  3566.         print HISTORYTMP "\n";
  3567.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'WormsShown'}</sortfor><comment>\n"; }
  3568.         print HISTORYTMP "# Worm ID - Hits - Bandwidth - Last visit\n";
  3569.         print HISTORYTMP "# The $MaxNbOf{'WormsShown'} first Hits must be first (order not required for others)\n";
  3570.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3571.         print HISTORYTMP "${xmlbb}BEGIN_WORMS${xmlbs}".(scalar keys %_worm_h)."${xmlbe}\n";
  3572.         # We save worm list in score sorted order to get a -output faster and with less use of memory.
  3573.         &BuildKeyList($MaxNbOf{'WormsShown'},$MinHit{'Worm'},\%_worm_h,\%_worm_h);
  3574.         my %keysinkeylist=();
  3575.         foreach (@keylist) {
  3576.             $keysinkeylist{$_}=1;
  3577.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_worm_h{$_})."${xmlrs}".int($_worm_k{$_})."${xmlrs}$_worm_l{$_}${xmlre}\n";
  3578.         }
  3579.         foreach (keys %_worm_h) {
  3580.             if ($keysinkeylist{$_}) { next; }
  3581.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_worm_h{$_})."${xmlrs}".int($_worm_k{$_})."${xmlrs}$_worm_l{$_}${xmlre}\n";
  3582.         }
  3583.         print HISTORYTMP "${xmleb}END_WORMS${xmlee}\n";
  3584.     }
  3585.     if ($sectiontosave eq 'emailsender') {
  3586.         print HISTORYTMP "\n";
  3587.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'EMailsShown'}</sortfor><comment>\n"; }
  3588.         print HISTORYTMP "# EMail - Hits - Bandwidth - Last visit\n";
  3589.         print HISTORYTMP "# The $MaxNbOf{'EMailsShown'} first Hits must be first (order not required for others)\n";
  3590.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3591.         print HISTORYTMP "${xmlbb}BEGIN_EMAILSENDER${xmlbs}".(scalar keys %_emails_h)."${xmlbe}\n";
  3592.         # We save sender email list in score sorted order to get a -output faster and with less use of memory.
  3593.         &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emails_h,\%_emails_h);
  3594.         my %keysinkeylist=();
  3595.         foreach (@keylist) {
  3596.             $keysinkeylist{$_}=1;
  3597.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emails_h{$_}||0)."${xmlrs}".int($_emails_k{$_}||0)."${xmlrs}$_emails_l{$_}${xmlre}\n";
  3598.         }
  3599.         foreach (keys %_emails_h) {
  3600.             if ($keysinkeylist{$_}) { next; }
  3601.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emails_h{$_}||0)."${xmlrs}".int($_emails_k{$_}||0)."${xmlrs}$_emails_l{$_}${xmlre}\n";
  3602.         }
  3603.         print HISTORYTMP "${xmleb}END_EMAILSENDER${xmlee}\n";
  3604.     }
  3605.     if ($sectiontosave eq 'emailreceiver') {
  3606.         print HISTORYTMP "\n";
  3607.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'EMailsShown'}</sortfor><comment>\n"; }
  3608.         print HISTORYTMP "# EMail - Hits - Bandwidth - Last visit\n";
  3609.         print HISTORYTMP "# The $MaxNbOf{'EMailsShown'} first hits must be first (order not required for others)\n";
  3610.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3611.         print HISTORYTMP "${xmlbb}BEGIN_EMAILRECEIVER${xmlbs}".(scalar keys %_emailr_h)."${xmlbe}\n";
  3612.         # We save receiver email list in score sorted order to get a -output faster and with less use of memory.
  3613.         &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emailr_h,\%_emailr_h);
  3614.         my %keysinkeylist=();
  3615.         foreach (@keylist) {
  3616.             $keysinkeylist{$_}=1;
  3617.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emailr_h{$_}||0)."${xmlrs}".int($_emailr_k{$_}||0)."${xmlrs}$_emailr_l{$_}${xmlre}\n";
  3618.         }
  3619.         foreach (keys %_emailr_h) {
  3620.             if ($keysinkeylist{$_}) { next; }
  3621.             print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_emailr_h{$_}||0)."${xmlrs}".int($_emailr_k{$_}||0)."${xmlrs}$_emailr_l{$_}${xmlre}\n";
  3622.         }
  3623.         print HISTORYTMP "${xmleb}END_EMAILRECEIVER${xmlee}\n";
  3624.     }
  3625.  
  3626.     # Navigation
  3627.     if ($sectiontosave eq 'session') {    # This section must be saved after VISITOR section is read
  3628.         print HISTORYTMP "\n";
  3629.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3630.         print HISTORYTMP "# Session range - Number of visits\n";
  3631.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3632.         print HISTORYTMP "${xmlbb}BEGIN_SESSION${xmlbs}".(scalar keys %_session)."${xmlbe}\n";
  3633.         foreach (keys %_session) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_session{$_})."${xmlre}\n"; }
  3634.         print HISTORYTMP "${xmleb}END_SESSION${xmlee}\n";
  3635.     }
  3636.     if ($sectiontosave eq 'sider') {    # This section must be saved after VISITOR section is read
  3637.         print HISTORYTMP "\n";
  3638.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'PageShown'}</sortfor><comment>\n"; }
  3639.         print HISTORYTMP "# URL - Pages - Bandwidth - Entry - Exit\n";
  3640.         print HISTORYTMP "# The $MaxNbOf{'PageShown'} first Pages must be first (order not required for others)\n";
  3641.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3642.         print HISTORYTMP "${xmlbb}BEGIN_SIDER${xmlbs}".(scalar keys %_url_p)."${xmlbe}\n";
  3643.         # We save page list in score sorted order to get a -output faster and with less use of memory.
  3644.         &BuildKeyList($MaxNbOf{'PageShown'},$MinHit{'File'},\%_url_p,\%_url_p);
  3645.         %keysinkeylist=();
  3646.         foreach (@keylist) {
  3647.             $keysinkeylist{$_}=1;
  3648.             my $newkey=$_;
  3649.             $newkey =~ s/([^:])\/\//$1\//g;        # Because some targeted url were taped with 2 / (Ex: //rep//file.htm). We must keep http://rep/file.htm
  3650.             print HISTORYTMP "${xmlrb}$newkey${xmlrs}".int($_url_p{$_}||0)."${xmlrs}".int($_url_k{$_}||0)."${xmlrs}".int($_url_e{$_}||0)."${xmlrs}".int($_url_x{$_}||0)."${xmlre}\n";
  3651.         }
  3652.         foreach (keys %_url_p) {
  3653.             if ($keysinkeylist{$_}) { next; }
  3654.             my $newkey=$_;
  3655.             $newkey =~ s/([^:])\/\//$1\//g;        # Because some targeted url were taped with 2 / (Ex: //rep//file.htm). We must keep http://rep/file.htm
  3656.             print HISTORYTMP "${xmlrb}$newkey ".int($_url_p{$_}||0)."${xmlrs}".int($_url_k{$_}||0)."${xmlrs}".int($_url_e{$_}||0)."${xmlrs}".int($_url_x{$_}||0)."${xmlre}\n";
  3657.         }
  3658.         print HISTORYTMP "${xmleb}END_SIDER${xmlee}\n";
  3659.     }
  3660.     if ($sectiontosave eq 'filetypes') {
  3661.         print HISTORYTMP "\n";
  3662.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3663.         print HISTORYTMP "# Files type - Hits - Bandwidth - Bandwidth without compression - Bandwidth after compression\n";
  3664.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3665.         print HISTORYTMP "${xmlbb}BEGIN_FILETYPES${xmlbs}".(scalar keys %_filetypes_h)."${xmlbe}\n";
  3666.         foreach (keys %_filetypes_h) {
  3667.             my $hits=$_filetypes_h{$_}||0;
  3668.             my $bytes=$_filetypes_k{$_}||0;
  3669.             my $bytesbefore=$_filetypes_gz_in{$_}||0;
  3670.             my $bytesafter=$_filetypes_gz_out{$_}||0;
  3671.             print HISTORYTMP "${xmlrb}$_${xmlrs}$hits${xmlrs}$bytes${xmlrs}$bytesbefore${xmlrs}$bytesafter${xmlre}\n";
  3672.         }
  3673.         print HISTORYTMP "${xmleb}END_FILETYPES${xmlee}\n";
  3674.     }
  3675.     if ($sectiontosave eq 'os') {
  3676.         print HISTORYTMP "\n";
  3677.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3678.         print HISTORYTMP "# OS ID - Hits\n";
  3679.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3680.         print HISTORYTMP "${xmlbb}BEGIN_OS${xmlbs}".(scalar keys %_os_h)."${xmlbe}\n";
  3681.         foreach (keys %_os_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_os_h{$_}${xmlre}\n"; }
  3682.         print HISTORYTMP "${xmleb}END_OS${xmlee}\n";
  3683.     }
  3684.     if ($sectiontosave eq 'browser') {
  3685.         print HISTORYTMP "\n";
  3686.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3687.         print HISTORYTMP "# Browser ID - Hits\n";
  3688.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3689.         print HISTORYTMP "${xmlbb}BEGIN_BROWSER${xmlbs}".(scalar keys %_browser_h)."${xmlbe}\n";
  3690.         foreach (keys %_browser_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_browser_h{$_}${xmlre}\n"; }
  3691.         print HISTORYTMP "${xmleb}END_BROWSER${xmlee}\n";
  3692.     }
  3693.     if ($sectiontosave eq 'screensize') {
  3694.         print HISTORYTMP "\n";
  3695.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3696.         print HISTORYTMP "# Screen size - Hits\n";
  3697.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3698.         print HISTORYTMP "${xmlbb}BEGIN_SCREENSIZE${xmlbs}".(scalar keys %_screensize_h)."${xmlbe}\n";
  3699.         foreach (keys %_screensize_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_screensize_h{$_}${xmlre}\n"; }
  3700.         print HISTORYTMP "${xmleb}END_SCREENSIZE${xmlee}\n";
  3701.     }
  3702.  
  3703.     # Referer
  3704.     if ($sectiontosave eq 'unknownreferer') {
  3705.         print HISTORYTMP "\n";
  3706.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3707.         print HISTORYTMP "# Unknown referer OS - Last visit date\n";
  3708.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3709.         print HISTORYTMP "${xmlbb}BEGIN_UNKNOWNREFERER${xmlbs}".(scalar keys %_unknownreferer_l)."${xmlbe}\n";
  3710.         foreach (keys %_unknownreferer_l) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_unknownreferer_l{$_}${xmlre}\n"; }
  3711.         print HISTORYTMP "${xmleb}END_UNKNOWNREFERER${xmlee}\n";
  3712.     }
  3713.     if ($sectiontosave eq 'unknownrefererbrowser') {
  3714.         print HISTORYTMP "\n";
  3715.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3716.         print HISTORYTMP "# Unknown referer Browser - Last visit date\n";
  3717.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3718.         print HISTORYTMP "${xmlbb}BEGIN_UNKNOWNREFERERBROWSER${xmlbs}".(scalar keys %_unknownrefererbrowser_l)."${xmlbe}\n";
  3719.         foreach (keys %_unknownrefererbrowser_l) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_unknownrefererbrowser_l{$_}${xmlre}\n"; }
  3720.         print HISTORYTMP "${xmleb}END_UNKNOWNREFERERBROWSER${xmlee}\n";
  3721.     }
  3722.     if ($sectiontosave eq 'origin') {
  3723.         print HISTORYTMP "\n";
  3724.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3725.         print HISTORYTMP "# Origin - Pages - Hits \n";
  3726.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3727.         print HISTORYTMP "${xmlbb}BEGIN_ORIGIN${xmlbs}6"."${xmlbe}\n";
  3728.         print HISTORYTMP "${xmlrb}From0${xmlrs}".int($_from_p[0])."${xmlrs}".int($_from_h[0])."${xmlre}\n";
  3729.         print HISTORYTMP "${xmlrb}From1${xmlrs}".int($_from_p[1])."${xmlrs}".int($_from_h[1])."${xmlre}\n";
  3730.         print HISTORYTMP "${xmlrb}From2${xmlrs}".int($_from_p[2])."${xmlrs}".int($_from_h[2])."${xmlre}\n";
  3731.         print HISTORYTMP "${xmlrb}From3${xmlrs}".int($_from_p[3])."${xmlrs}".int($_from_h[3])."${xmlre}\n";
  3732.         print HISTORYTMP "${xmlrb}From4${xmlrs}".int($_from_p[4])."${xmlrs}".int($_from_h[4])."${xmlre}\n";        # Same site
  3733.         print HISTORYTMP "${xmlrb}From5${xmlrs}".int($_from_p[5])."${xmlrs}".int($_from_h[5])."${xmlre}\n";        # News
  3734.         print HISTORYTMP "${xmleb}END_ORIGIN${xmlee}\n";
  3735.     }
  3736.     if ($sectiontosave eq 'sereferrals') {
  3737.         print HISTORYTMP "\n";
  3738.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3739.         print HISTORYTMP "# Search engine referers ID - Pages - Hits\n";
  3740.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3741.         print HISTORYTMP "${xmlbb}BEGIN_SEREFERRALS${xmlbs}".(scalar keys %_se_referrals_h)."${xmlbe}\n";
  3742.         foreach (keys %_se_referrals_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_se_referrals_p{$_}||0)."${xmlrs}$_se_referrals_h{$_}${xmlre}\n"; }
  3743.         print HISTORYTMP "${xmleb}END_SEREFERRALS${xmlee}\n";
  3744.     }
  3745.     if ($sectiontosave eq 'pagerefs') {
  3746.         print HISTORYTMP "\n";
  3747.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'RefererShown'}</sortfor><comment>\n"; }
  3748.         print HISTORYTMP "# External page referers - Pages - Hits\n";
  3749.         print HISTORYTMP "# The $MaxNbOf{'RefererShown'} first Pages must be first (order not required for others)\n";
  3750.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3751.         print HISTORYTMP "${xmlbb}BEGIN_PAGEREFS${xmlbs}".(scalar keys %_pagesrefs_h)."${xmlbe}\n";
  3752.         # We save page list in score sorted order to get a -output faster and with less use of memory.
  3753.         &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_pagesrefs_h,\%_pagesrefs_p);
  3754.         %keysinkeylist=();
  3755.         foreach (@keylist) {
  3756.             $keysinkeylist{$_}=1;
  3757.             my $newkey=$_;
  3758.             $newkey =~ s/^http(s|):\/\/([^\/]+)\/$/http$1:\/\/$2/i;    # Remove / at end of http://.../ but not at end of http://.../dir/
  3759.             print HISTORYTMP "${xmlrb}".XMLEncodeForH($newkey)."${xmlrs}".int($_pagesrefs_p{$_}||0)."${xmlrs}$_pagesrefs_h{$_}${xmlre}\n";
  3760.         }
  3761.         foreach (keys %_pagesrefs_h) {
  3762.             if ($keysinkeylist{$_}) { next; }
  3763.             my $newkey=$_;
  3764.             $newkey =~ s/^http(s|):\/\/([^\/]+)\/$/http$1:\/\/$2/i;    # Remove / at end of http://.../ but not at end of http://.../dir/
  3765.             print HISTORYTMP "${xmlrb}".XMLEncodeForH($newkey)."${xmlrs}".int($_pagesrefs_p{$_}||0)."${xmlrs}$_pagesrefs_h{$_}${xmlre}\n";
  3766.         }
  3767.         print HISTORYTMP "${xmleb}END_PAGEREFS${xmlee}\n";
  3768.     }
  3769.     if ($sectiontosave eq 'searchwords') {
  3770.         print HISTORYTMP "\n";
  3771.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOf{'KeyphrasesShown'}</sortfor><comment>\n"; }
  3772.         print HISTORYTMP "# Search keyphrases - Number of search\n";
  3773.         print HISTORYTMP "# The $MaxNbOf{'KeyphrasesShown'} first number of search must be first (order not required for others)\n";
  3774.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3775.         print HISTORYTMP "${xmlbb}BEGIN_SEARCHWORDS${xmlbs}".(scalar keys %_keyphrases)."${xmlbe}\n";
  3776.         # We will also build _keywords
  3777.         %_keywords=();
  3778.         # We save key list in score sorted order to get a -output faster and with less use of memory.
  3779.         &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keyphrases,\%_keyphrases);
  3780.         %keysinkeylist=();
  3781.         foreach my $key (@keylist) {
  3782.             $keysinkeylist{$key}=1;
  3783.             my $keyphrase=$key;
  3784.             print HISTORYTMP "${xmlrb}$keyphrase${xmlrs}$_keyphrases{$key}${xmlre}\n";
  3785.             foreach (split(/\+/,$key)) { $_keywords{$_}+=$_keyphrases{$key}; }    # To init %_keywords
  3786.         }
  3787.         foreach my $key (keys %_keyphrases) {
  3788.             if ($keysinkeylist{$key}) { next; }
  3789.             my $keyphrase=$key;
  3790.             print HISTORYTMP "${xmlrb}$keyphrase${xmlrs}$_keyphrases{$key}${xmlre}\n";
  3791.             foreach (split(/\+/,$key)) { $_keywords{$_}+=$_keyphrases{$key}; }    # To init %_keywords
  3792.         }
  3793.         print HISTORYTMP "${xmleb}END_SEARCHWORDS${xmlee}\n";
  3794.  
  3795.         # Now save keywords section
  3796.         print HISTORYTMP "\n";
  3797.         if ($xml) { print HISTORYTMP "<section id='keywords'><sortfor>$MaxNbOf{'KeywordsShown'}</sortfor><comment>\n"; }
  3798.         print HISTORYTMP "# Search keywords - Number of search\n";
  3799.         print HISTORYTMP "# The $MaxNbOf{'KeywordsShown'} first number of search must be first (order not required for others)\n";
  3800.         $ValueInFile{"keywords"}=tell HISTORYTMP;
  3801.         print HISTORYTMP "${xmlbb}BEGIN_KEYWORDS${xmlbs}".(scalar keys %_keywords)."${xmlbe}\n";
  3802.         # We save key list in score sorted order to get a -output faster and with less use of memory.
  3803.         &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keywords,\%_keywords);
  3804.         %keysinkeylist=();
  3805.         foreach (@keylist) {
  3806.             $keysinkeylist{$_}=1;
  3807.             my $keyword=$_;
  3808.             print HISTORYTMP "${xmlrb}$keyword${xmlrs}$_keywords{$_}${xmlre}\n";
  3809.         }
  3810.         foreach (keys %_keywords) {
  3811.             if ($keysinkeylist{$_}) { next; }
  3812.             my $keyword=$_;
  3813.             print HISTORYTMP "${xmlrb}$keyword${xmlrs}$_keywords{$_}${xmlre}\n";
  3814.         }
  3815.         print HISTORYTMP "${xmleb}END_KEYWORDS${xmlee}\n";
  3816.  
  3817.     }
  3818.  
  3819.     # Other - Errors
  3820.     if ($sectiontosave eq 'cluster') {
  3821.         print HISTORYTMP "\n";
  3822.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3823.         print HISTORYTMP "# Cluster ID - Pages - Hits - Bandwidth\n";
  3824.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3825.         print HISTORYTMP "${xmlbb}BEGIN_CLUSTER${xmlbs}".(scalar keys %_cluster_h)."${xmlbe}\n";
  3826.         foreach (keys %_cluster_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_cluster_p{$_}||0)."${xmlrs}".int($_cluster_h{$_}||0)."${xmlrs}".int($_cluster_k{$_}||0)."${xmlre}\n"; }
  3827.         print HISTORYTMP "${xmleb}END_CLUSTER${xmlee}\n";
  3828.     }
  3829.     if ($sectiontosave eq 'misc') {
  3830.         print HISTORYTMP "\n";
  3831.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3832.         print HISTORYTMP "# Misc ID - Pages - Hits - Bandwidth\n";
  3833.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3834.         print HISTORYTMP "${xmlbb}BEGIN_MISC${xmlbs}".(scalar keys %MiscListCalc)."${xmlbe}\n";
  3835.         foreach (keys %MiscListCalc) { print HISTORYTMP "${xmlrb}$_${xmlrs}".int($_misc_p{$_}||0)."${xmlrs}".int($_misc_h{$_}||0)."${xmlrs}".int($_misc_k{$_}||0)."${xmlre}\n"; }
  3836.         print HISTORYTMP "${xmleb}END_MISC${xmlee}\n";
  3837.     }
  3838.     if ($sectiontosave eq 'errors') {
  3839.         print HISTORYTMP "\n";
  3840.         if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3841.         print HISTORYTMP "# Errors - Hits - Bandwidth\n";
  3842.         $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3843.         print HISTORYTMP "${xmlbb}BEGIN_ERRORS${xmlbs}".(scalar keys %_errors_h)."${xmlbe}\n";
  3844.         foreach (keys %_errors_h) { print HISTORYTMP "${xmlrb}$_${xmlrs}$_errors_h{$_}${xmlrs}".int($_errors_k{$_}||0)."${xmlre}\n"; }
  3845.         print HISTORYTMP "${xmleb}END_ERRORS${xmlee}\n";
  3846.     }
  3847.      # Other - Trapped errors
  3848.     foreach my $code (keys %TrapInfosForHTTPErrorCodes) {
  3849.         if ($sectiontosave eq "sider_$code") {
  3850.             print HISTORYTMP "\n";
  3851.             if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><comment>\n"; }
  3852.             print HISTORYTMP "# URL with $code errors - Hits - Last URL referer\n";
  3853.             $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3854.             print HISTORYTMP "${xmlbb}BEGIN_SIDER_$code${xmlbs}".(scalar keys %_sider404_h)."${xmlbe}\n";
  3855.             foreach (keys %_sider404_h) {
  3856.                 my $newkey=$_;
  3857.                 my $newreferer=$_referer404_h{$_}||'';
  3858.                 print HISTORYTMP "${xmlrb}".XMLEncodeForH($newkey)."${xmlrs}$_sider404_h{$_}${xmlrs}".XMLEncodeForH($newreferer)."${xmlre}\n";
  3859.             }
  3860.             print HISTORYTMP "${xmleb}END_SIDER_$code${xmlee}\n";
  3861.         }
  3862.     }
  3863.      # Other - Extra stats sections
  3864.      foreach my $extranum (1..@ExtraName-1) {
  3865.         if ($sectiontosave eq "extra_$extranum") {
  3866.             print HISTORYTMP "\n";
  3867.             if ($xml) { print HISTORYTMP "<section id='$sectiontosave'><sortfor>$MaxNbOfExtra[$extranum]</sortfor><comment>\n"; }
  3868.             print HISTORYTMP "# Extra key - Pages - Hits - Bandwidth - Last access\n";
  3869.             print HISTORYTMP "# The $MaxNbOfExtra[$extranum] first number of hits are first\n";
  3870.             $ValueInFile{$sectiontosave}=tell HISTORYTMP;
  3871.              print HISTORYTMP "${xmlbb}BEGIN_EXTRA_$extranum${xmlbs}".scalar (keys %{'_section_' . $extranum . '_h'})."${xmlbe}\n";
  3872.              &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_p'});
  3873.              %keysinkeylist=();
  3874.              foreach (@keylist) {
  3875.                  $keysinkeylist{$_}=1;
  3876.                  my $page=${'_section_' . $extranum . '_p'}{$_}||0;
  3877.                  my $bytes=${'_section_' . $extranum . '_k'}{$_}||0;
  3878.                  my $lastaccess=${'_section_' . $extranum . '_l'}{$_}||'';
  3879.                  print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}", ${'_section_' . $extranum . '_h'}{$_}, "${xmlrs}$bytes${xmlrs}$lastaccess${xmlre}\n"; next;
  3880.              }
  3881.              foreach (keys %{'_section_' . $extranum . '_h'}) {
  3882.                  if ($keysinkeylist{$_}) { next; }
  3883.                  my $page=${'_section_' . $extranum . '_p'}{$_}||0;
  3884.                  my $bytes=${'_section_' . $extranum . '_k'}{$_}||0;
  3885.                  my $lastaccess=${'_section_' . $extranum . '_l'}{$_}||'';
  3886.                  print HISTORYTMP "${xmlrb}$_${xmlrs}$page${xmlrs}", ${'_section_' . $extranum . '_h'}{$_}, "${xmlrs}$bytes${xmlrs}$lastaccess${xmlre}\n"; next;
  3887.              }
  3888.              print HISTORYTMP "${xmleb}END_EXTRA_$extranum${xmlee}\n";
  3889.         }
  3890.      }
  3891.     
  3892.     %keysinkeylist=();
  3893. }
  3894.  
  3895. #--------------------------------------------------------------------
  3896. # Function:     Rename all tmp history file into history
  3897. # Parameters:   None
  3898. # Input:        $DirData $PROG $FileSuffix
  3899. #               $KeepBackupOfHistoricFile $SaveDatabaseFilesWithPermissionsForEveryone
  3900. # Output:       None
  3901. # Return:       1 Ok, 0 at least one error (tmp files are removed)
  3902. #--------------------------------------------------------------------
  3903. sub Rename_All_Tmp_History {
  3904.     my $pid=$$;
  3905.     my $renameok=1;
  3906.  
  3907.     if ($Debug) { debug("Call to Rename_All_Tmp_History"); }
  3908.  
  3909.     opendir(DIR,"$DirData");
  3910.     foreach (grep /^$PROG(\d\d\d\d\d\d)$FileSuffix\.tmp\.$pid$/, sort readdir DIR) {
  3911.         /^$PROG(\d\d\d\d\d\d)$FileSuffix\.tmp\.$pid$/;
  3912.         if ($renameok) {    # No rename error yet
  3913.             if ($Debug) { debug(" Rename new tmp history file $PROG$1$FileSuffix.tmp.$$ into $PROG$1$FileSuffix.txt",1); }
  3914.             if (-s "$DirData/$PROG$1$FileSuffix.tmp.$$") {        # Rename tmp files if size > 0
  3915.                 if ($KeepBackupOfHistoricFiles) {
  3916.                     if (-s "$DirData/$PROG$1$FileSuffix.txt") {    # History file already exists. We backup it
  3917.                         if ($Debug) { debug("  Make a backup of old history file into $PROG$1$FileSuffix.bak before",1); }
  3918.                         #if (FileCopy("$DirData/$PROG$1$FileSuffix.txt","$DirData/$PROG$1$FileSuffix.bak")) {
  3919.                         if (rename("$DirData/$PROG$1$FileSuffix.txt", "$DirData/$PROG$1$FileSuffix.bak")==0) {
  3920.                             warning("Warning: Failed to make a backup of \"$DirData/$PROG$1$FileSuffix.txt\" into \"$DirData/$PROG$1$FileSuffix.bak\".");
  3921.                         }
  3922.                         if ($SaveDatabaseFilesWithPermissionsForEveryone) {
  3923.                             chmod 0666,"$DirData/$PROG$1$FileSuffix.bak";
  3924.                         }
  3925.                     }
  3926.                     else {
  3927.                         if ($Debug) { debug("  No need to backup old history file",1); }
  3928.                     }
  3929.                 }
  3930.                 if (rename("$DirData/$PROG$1$FileSuffix.tmp.$$", "$DirData/$PROG$1$FileSuffix.txt")==0) {
  3931.                     $renameok=0;    # At least one error in renaming working files
  3932.                     # Remove tmp file
  3933.                     unlink "$DirData/$PROG$1$FileSuffix.tmp.$$";
  3934.                     warning("Warning: Failed to rename \"$DirData/$PROG$1$FileSuffix.tmp.$$\" into \"$DirData/$PROG$1$FileSuffix.txt\".\nWrite permissions on \"$PROG$1$FileSuffix.txt\" might be wrong".($ENV{'GATEWAY_INTERFACE'}?" for an 'update from web'":"")." or file might be opened.");
  3935.                     next;
  3936.                 }
  3937.                 if ($SaveDatabaseFilesWithPermissionsForEveryone) {
  3938.                     chmod 0666,"$DirData/$PROG$1$FileSuffix.txt";
  3939.                 }
  3940.             }
  3941.         }
  3942.         else {                # Because of rename error, we remove all remaining tmp files
  3943.             unlink "$DirData/$PROG$1$FileSuffix.tmp.$$";
  3944.         }
  3945.     }
  3946.     close DIR;
  3947.     return $renameok;
  3948. }
  3949.  
  3950. #------------------------------------------------------------------------------
  3951. # Function:     Load DNS cache file entries into a memory hash array
  3952. # Parameters:    Hash array ref to load into,
  3953. #               File name to load,
  3954. #                File suffix to use
  3955. #               Save to a second plugin file if not up to date
  3956. # Input:        None
  3957. # Output:        Hash array is loaded
  3958. # Return:        1 No DNS Cache file found, 0 OK
  3959. #------------------------------------------------------------------------------
  3960. sub Read_DNS_Cache {
  3961.     my $hashtoload=shift;
  3962.     my $dnscachefile=shift;
  3963.     my $filesuffix=shift;
  3964.     my $savetohash=shift;
  3965.  
  3966.     my $dnscacheext='';
  3967.     my $filetoload='';
  3968.     my $timetoload = time();
  3969.  
  3970.     if ($Debug) { debug("Call to Read_DNS_Cache [file=\"$dnscachefile\"]"); }
  3971.     if ($dnscachefile =~ s/(\.\w+)$//) { $dnscacheext=$1; }
  3972.     foreach my $dir ("$DirData",".","") {
  3973.         my $searchdir=$dir;
  3974.         if ($searchdir && (!($searchdir =~ /\/$/)) && (!($searchdir =~ /\\$/)) ) { $searchdir .= "/"; }
  3975.         if (-f "${searchdir}$dnscachefile$filesuffix$dnscacheext") { $filetoload="${searchdir}$dnscachefile$filesuffix$dnscacheext"; }
  3976.         # Plugin call : Change filetoload
  3977.         if ($PluginsLoaded{'SearchFile'}{'hashfiles'}) { SearchFile_hashfiles($searchdir,$dnscachefile,$filesuffix,$dnscacheext,$filetoload); }
  3978.         if ($filetoload) { last; }    # We found a file to load
  3979.     }
  3980.  
  3981.     if (! $filetoload) {
  3982.         if ($Debug) { debug(" No DNS Cache file found"); }
  3983.         return 1;
  3984.     }
  3985.  
  3986.     # Plugin call : Load hashtoload
  3987.     if ($PluginsLoaded{'LoadCache'}{'hashfiles'}) { LoadCache_hashfiles($filetoload,$hashtoload); }
  3988.     if (! scalar keys %$hashtoload) {
  3989.         open(DNSFILE,"$filetoload") or error("Couldn't open DNS Cache file \"$filetoload\": $!");
  3990.         #binmode DNSFILE;        # If we set binmode here, it seems that the load is broken on ActiveState 5.8
  3991.         # This is a fast way to load with regexp
  3992.         %$hashtoload = map(/^(?:\d{0,10}\s+)?([0-9A-F:\.]+)\s+([^\s]+)$/oi,<DNSFILE>);
  3993.         close DNSFILE;
  3994.         if ($savetohash) {
  3995.             # Plugin call : Save hash file (all records) with test if up to date to save
  3996.             if ($PluginsLoaded{'SaveHash'}{'hashfiles'}) { SaveHash_hashfiles($filetoload,$hashtoload,1,0); }
  3997.         }
  3998.     }
  3999.     if ($Debug) { debug(" Loaded ".(scalar keys %$hashtoload)." items from $filetoload in ".(time()-$timetoload)." seconds.",1); }
  4000.     return 0;
  4001. }
  4002.  
  4003. #------------------------------------------------------------------------------
  4004. # Function:     Save a memory hash array into a DNS cache file
  4005. # Parameters:    Hash array ref to save,
  4006. #               File name to save,
  4007. #                File suffix to use
  4008. # Input:        None
  4009. # Output:        None
  4010. # Return:        0 OK, 1 Error
  4011. #------------------------------------------------------------------------------
  4012. sub Save_DNS_Cache_File {
  4013.     my $hashtosave=shift;
  4014.     my $dnscachefile=shift;
  4015.     my $filesuffix=shift;
  4016.  
  4017.     my $dnscacheext='';
  4018.     my $filetosave='';
  4019.     my $timetosave = time();
  4020.     my $nbofelemtosave=$NBOFLASTUPDATELOOKUPTOSAVE;
  4021.     my $nbofelemsaved=0;
  4022.  
  4023.     if ($Debug) { debug("Call to Save_DNS_Cache_File [file=\"$dnscachefile\"]"); }
  4024.     if (! scalar keys %$hashtosave) {
  4025.         if ($Debug) { debug(" No data to save"); }
  4026.         return 0;
  4027.     }
  4028.     if ($dnscachefile =~ s/(\.\w+)$//) { $dnscacheext=$1; }
  4029.     $filetosave="$dnscachefile$filesuffix$dnscacheext";
  4030.     # Plugin call : Save hash file (only $NBOFLASTUPDATELOOKUPTOSAVE records) with no test if up to date
  4031.     if ($PluginsLoaded{'SaveHash'}{'hashfiles'}) { SaveHash_hashfiles($filetosave,$hashtosave,0,$nbofelemtosave,$nbofelemsaved); }
  4032.     if (! $nbofelemsaved) {
  4033.         $filetosave="$dnscachefile$filesuffix$dnscacheext";
  4034.         if ($Debug) { debug(" Save data ".($nbofelemtosave?"($nbofelemtosave records max)":"(all records)")." into file $filetosave"); }
  4035.         if (! open(DNSFILE,">$filetosave")) {
  4036.             warning("Warning: Failed to open for writing last update DNS Cache file \"$filetosave\": $!");
  4037.             return 1;
  4038.         }
  4039.         binmode DNSFILE;
  4040.         my $starttimemin=int($starttime/60);
  4041.         foreach my $key (keys %$hashtosave) {
  4042.             #if ($hashtosave->{$key} ne '*') {
  4043.                 my $ipsolved=$hashtosave->{$key};
  4044.                 print DNSFILE "$starttimemin\t$key\t".($ipsolved eq 'ip'?'*':$ipsolved)."\n";    # Change 'ip' to '*' for backward compatibility
  4045.                 if (++$nbofelemsaved >= $NBOFLASTUPDATELOOKUPTOSAVE) { last; }
  4046.             #}
  4047.         }
  4048.         close DNSFILE;
  4049.         
  4050.         if ($SaveDatabaseFilesWithPermissionsForEveryone) {
  4051.             chmod 0666,"$filetosave";
  4052.         }
  4053.  
  4054.     }
  4055.     if ($Debug) { debug(" Saved $nbofelemsaved items into $filetosave in ".(time()-$timetosave)." seconds.",1); }
  4056.     return 0;
  4057. }
  4058.  
  4059. #------------------------------------------------------------------------------
  4060. # Function:     Return time elapsed since last call in miliseconds
  4061. # Parameters:    0|1 (0 reset counter, 1 no reset)
  4062. # Input:        None
  4063. # Output:        None
  4064. # Return:        Number of miliseconds elapsed since last call
  4065. #------------------------------------------------------------------------------
  4066. sub GetDelaySinceStart {
  4067.     if (shift) { $StartSeconds=0; }    # Reset chrono
  4068.     my ($newseconds, $newmicroseconds)=(time(),0);
  4069.     # Plugin call : Return seconds and milliseconds
  4070.     if ($PluginsLoaded{'GetTime'}{'timehires'}) { GetTime_timehires($newseconds, $newmicroseconds); }
  4071.     if (! $StartSeconds) { $StartSeconds=$newseconds; $StartMicroseconds=$newmicroseconds; }
  4072.     return (($newseconds-$StartSeconds)*1000+int(($newmicroseconds-$StartMicroseconds)/1000));
  4073. }
  4074.  
  4075. #------------------------------------------------------------------------------
  4076. # Function:     Reset all variables whose name start with _ because a new month start
  4077. # Parameters:    None
  4078. # Input:        $YearRequired All variables whose name start with _
  4079. # Output:       All variables whose name start with _
  4080. # Return:        None
  4081. #------------------------------------------------------------------------------
  4082. sub Init_HashArray {
  4083.     if ($Debug) { debug("Call to Init_HashArray"); }
  4084.     # Reset global hash arrays
  4085.     %FirstTime = %LastTime = ();
  4086.     %MonthHostsKnown = %MonthHostsUnknown = ();
  4087.     %MonthVisits = %MonthUnique = ();
  4088.     %MonthPages = %MonthHits = %MonthBytes = ();
  4089.     %MonthNotViewedPages = %MonthNotViewedHits = %MonthNotViewedBytes = ();
  4090.     %DayPages = %DayHits = %DayBytes = %DayVisits = ();
  4091.     # Reset all arrays with name beginning by _
  4092.     for (my $ix=0; $ix<6; $ix++)  { $_from_p[$ix]=0; $_from_h[$ix]=0; }
  4093.     for (my $ix=0; $ix<24; $ix++) { $_time_h[$ix]=0; $_time_k[$ix]=0; $_time_p[$ix]=0; $_time_nv_h[$ix]=0; $_time_nv_k[$ix]=0; $_time_nv_p[$ix]=0; }
  4094.     # Reset all hash arrays with name beginning by _
  4095.     %_session = %_browser_h = ();
  4096.     %_domener_p = %_domener_h = %_domener_k = %_errors_h = %_errors_k = ();
  4097.     %_filetypes_h = %_filetypes_k = %_filetypes_gz_in = %_filetypes_gz_out = ();
  4098.     %_host_p = %_host_h = %_host_k = %_host_l = %_host_s = %_host_u = ();
  4099.     %_waithost_e = %_waithost_l = %_waithost_s = %_waithost_u = ();
  4100.     %_keyphrases = %_keywords = %_os_h = %_pagesrefs_p = %_pagesrefs_h = %_robot_h = %_robot_k = %_robot_l = %_robot_r = ();
  4101.     %_worm_h = %_worm_k = %_worm_l = %_login_p = %_login_h = %_login_k = %_login_l = %_screensize_h = ();
  4102.      %_misc_p = %_misc_h = %_misc_k = ();
  4103.     %_cluster_p = %_cluster_h = %_cluster_k = ();
  4104.     %_se_referrals_p = %_se_referrals_h = %_sider404_h = %_referer404_h = %_url_p = %_url_k = %_url_e = %_url_x = ();
  4105.     %_unknownreferer_l = %_unknownrefererbrowser_l = ();
  4106.     %_emails_h = %_emails_k = %_emails_l = %_emailr_h = %_emailr_k = %_emailr_l = ();
  4107.      for (my $ix=1; $ix < @ExtraName; $ix++) {
  4108.          %{'_section_' . $ix . '_h'} = %{'_section_' . $ix . '_o'} = %{'_section_' . $ix . '_k'}    =
  4109.          %{'_section_' . $ix . '_l'} = %{'_section_' . $ix . '_p'} = ();
  4110.      }
  4111. }
  4112.  
  4113. #------------------------------------------------------------------------------
  4114. # Function:     Change word separators of a keyphrase string into space and
  4115. #               remove bad coded chars
  4116. # Parameters:    stringtodecode
  4117. # Input:        None
  4118. # Output:       None
  4119. # Return:        decodedstring
  4120. #------------------------------------------------------------------------------
  4121. sub ChangeWordSeparatorsIntoSpace {
  4122.     $_[0] =~ s/%0[ad]/ /ig;                # LF,CR
  4123.     $_[0] =~ s/%2[02789abc]/ /ig;        # 
  4124.     $_[0] =~ s/%3a/ /ig;                # :
  4125.     $_[0] =~ tr/\+\'\(\)\"\*,:/        /s;        # "&" and "=" must not be in this list
  4126. }
  4127.  
  4128. #------------------------------------------------------------------------------
  4129. # Function:        Transforms & into & as needed in XML/XHTML
  4130. # Parameters:    stringtoencode
  4131. # Return:        encodedstring
  4132. #------------------------------------------------------------------------------
  4133. sub XMLEncode {
  4134.     if ($BuildReportFormat ne 'xhtml' && $BuildReportFormat ne 'xml') { return shift; }
  4135.     my $string = shift;
  4136.     $string =~ s/&/&/g;
  4137.     return $string;
  4138. }
  4139.  
  4140. #------------------------------------------------------------------------------
  4141. # Function:        Transforms & into & as needed in XML/XHTML
  4142. # Parameters:    stringtoencode
  4143. # Return:        encodedstring
  4144. #------------------------------------------------------------------------------
  4145. sub XMLEncodeForH {
  4146.     my $string = shift;
  4147.     $string =~ s/\s/%20/g;
  4148.     if ($BuildHistoryFormat ne 'xml') { return $string; }
  4149.     $string =~ s/&/&/g;
  4150.     $string =~ s/</</g;
  4151.     $string =~ s/>/>/g;
  4152.     return $string;
  4153. }
  4154.  
  4155. #------------------------------------------------------------------------------
  4156. # Function:     Encode a binary string into an ASCII string
  4157. # Parameters:    stringtoencode
  4158. # Return:        encodedstring
  4159. #------------------------------------------------------------------------------
  4160. sub EncodeString {
  4161.     my $string = shift;
  4162. #    use bytes;
  4163.     $string =~ s/([\x2B\x80-\xFF])/sprintf ("%%%2x", ord($1))/eg;
  4164. #    no bytes;
  4165.     $string =~ tr/ /+/s;
  4166.     return $string;
  4167. }
  4168.  
  4169. #------------------------------------------------------------------------------
  4170. # Function:     Decode an only text string into a binary string
  4171. # Parameters:   stringtodecode
  4172. # Input:        None
  4173. # Output:       None
  4174. # Return:        decodedstring
  4175. #------------------------------------------------------------------------------
  4176. sub DecodeEncodedString {
  4177.     my $stringtodecode=shift;
  4178.     $stringtodecode =~ tr/\+/ /s;
  4179.     $stringtodecode =~ s/%([A-F0-9][A-F0-9])/pack("C", hex($1))/ieg;
  4180.     return $stringtodecode;
  4181. }
  4182.  
  4183. #------------------------------------------------------------------------------
  4184. # Function:     Decode an precompiled regex value to a common regex value
  4185. # Parameters:   compiledregextodecode
  4186. # Input:        None
  4187. # Output:       None
  4188. # Return:        standardregex
  4189. #------------------------------------------------------------------------------
  4190. sub UnCompileRegex {
  4191.     shift =~ /\(\?[-\w]*:(.*)\)/;
  4192.     return $1;
  4193. }
  4194.  
  4195. #------------------------------------------------------------------------------
  4196. # Function:     Clean a string of HTML tags to avoid 'Cross Site Scripting attacks'
  4197. # Parameters:   stringtodecode
  4198. # Input:        None
  4199. # Output:       None
  4200. # Return:        decodedstring
  4201. #------------------------------------------------------------------------------
  4202. sub CleanFromCSSA {
  4203.     my $stringtoclean=shift;
  4204.     $stringtoclean =~ s/</</g;
  4205.     $stringtoclean =~ s/>/>/g;
  4206.     return $stringtoclean;
  4207. }
  4208.  
  4209. #------------------------------------------------------------------------------
  4210. # Function:     Clean tags in a string
  4211. # Parameters:   stringtodecode
  4212. # Input:        None
  4213. # Output:       None
  4214. # Return:        decodedstring
  4215. #------------------------------------------------------------------------------
  4216. sub CleanFromTags {
  4217.     my $stringtoclean=shift;
  4218.     $stringtoclean =~ s/$regclean1/ /g;    # Replace <recnb> or </td> with space
  4219.     $stringtoclean =~ s/$regclean2//g;    # Remove <xxx>
  4220.     return $stringtoclean;
  4221. }
  4222.  
  4223. #------------------------------------------------------------------------------
  4224. # Function:     Copy one file into another
  4225. # Parameters:   sourcefilename targetfilename
  4226. # Input:        None
  4227. # Output:       None
  4228. # Return:        0 if copy is ok, 1 else
  4229. #------------------------------------------------------------------------------
  4230. sub FileCopy {
  4231.     my $filesource = shift;
  4232.     my $filetarget = shift;
  4233.     if ($Debug) { debug("FileCopy($filesource,$filetarget)",1); }
  4234.     open(FILESOURCE,"$filesource") || return 1;
  4235.     open(FILETARGET,">$filetarget") || return 1;
  4236.     binmode FILESOURCE;
  4237.     binmode FILETARGET;
  4238.     # ...
  4239.     close(FILETARGET);
  4240.     close(FILESOURCE);
  4241.     if ($Debug) { debug(" File copied",1); }
  4242.     return 0;
  4243. }
  4244.  
  4245. #------------------------------------------------------------------------------
  4246. # Function:     Show flags for other language translations
  4247. # Parameters:   Current languade id (en, fr, ...)
  4248. # Input:        None
  4249. # Output:       None
  4250. # Return:       None
  4251. #------------------------------------------------------------------------------
  4252. sub Show_Flag_Links {
  4253.     my $CurrentLang = shift;
  4254.  
  4255.     # Build flags link
  4256.     my $NewLinkParams=$QueryString;
  4257.     my $NewLinkTarget='';
  4258.     if ($ENV{'GATEWAY_INTERFACE'}) {
  4259.         $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  4260.         $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  4261.         $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  4262.         $NewLinkParams =~ s/(^|&)lang=[^&]*//i;
  4263.         if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; }
  4264.         $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  4265.         if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  4266.     }
  4267.     else {
  4268.         $NewLinkParams=($SiteConfig?"config=$SiteConfig&":"")."year=$YearRequired&month=$MonthRequired&";
  4269.     }
  4270.     if ($FrameName eq 'mainright') { $NewLinkParams.='framename=index&'; }
  4271.  
  4272.     foreach my $lng (split(/\s+/,$ShowFlagLinks)) {
  4273.         if ($lng ne $CurrentLang) {
  4274.             my %lngtitle=('en','English','fr','French','de','German','it','Italian','nl','Dutch','es','Spanish');
  4275.             my $lngtitle=($lngtitle{$lng}?$lngtitle{$lng}:$lng);
  4276.             my $flag=($LangAWStatsToCountryAwstats{$lng}?$LangAWStatsToCountryAwstats{$lng}:$lng);
  4277.             print "<a href=\"".XMLEncode("$AWScript?${NewLinkParams}lang=$lng")."\"$NewLinkTarget><img src=\"$DirIcons\/flags\/$flag.png\" height=\"14\" border=\"0\"".AltTitle("$lngtitle")." /></a> \n";
  4278.         }
  4279.     }
  4280. }
  4281.  
  4282. #------------------------------------------------------------------------------
  4283. # Function:        Format value in bytes in a string (Bytes, Kb, Mb, Gb)
  4284. # Parameters:   bytes (integer value or "0.00")
  4285. # Input:        None
  4286. # Output:       None
  4287. # Return:       "x.yz MB" or "x.yy KB" or "x Bytes" or "0"
  4288. #------------------------------------------------------------------------------
  4289. sub Format_Bytes {
  4290.     my $bytes = shift||0;
  4291.     my $fudge = 1;
  4292.     # Do not use exp/log function to calculate 1024power, function make segfault on some unix/perl versions
  4293.     if ($bytes >= ($fudge << 30)) { return sprintf("%.2f", $bytes/1073741824)." $Message[110]"; }
  4294.     if ($bytes >= ($fudge << 20)) { return sprintf("%.2f", $bytes/1048576)." $Message[109]"; }
  4295.     if ($bytes >= ($fudge << 10)) { return sprintf("%.2f", $bytes/1024)." $Message[108]"; }
  4296.     if ($bytes < 0) { $bytes="?"; }
  4297.     return int($bytes).(int($bytes)?" $Message[119]":"");
  4298. }
  4299.  
  4300. #------------------------------------------------------------------------------
  4301. # Function:        Return " alt=string title=string"
  4302. # Parameters:   string
  4303. # Input:        None
  4304. # Output:       None
  4305. # Return:       "alt=string title=string"
  4306. #------------------------------------------------------------------------------
  4307. sub AltTitle {
  4308.     my $string = shift||'';
  4309.     return " alt='$string' title='$string'";
  4310. #    return " alt=\"$string\" title=\"$string\"";
  4311. #    return ($BuildReportFormat?"":" alt=\"$string\"")." title=\"$string\"";
  4312. }
  4313.  
  4314. #------------------------------------------------------------------------------
  4315. # Function:        Tell if an email is a local or external email
  4316. # Parameters:   email
  4317. # Input:        $SiteDomain(exact string) $HostAliases(quoted regex string)
  4318. # Output:       None
  4319. # Return:       -1, 0 or 1
  4320. #------------------------------------------------------------------------------
  4321. sub IsLocalEMail {
  4322.     my $email=shift||'unknown';
  4323.     if ($email !~ /\@(.*)$/) { return 0; }
  4324.     my $domain=$1;
  4325.     if ($domain =~ /^$SiteDomain$/i) { return 1; }
  4326.     foreach (@HostAliases) { if ($domain =~ /$_/) { return 1; } }
  4327.     return -1;
  4328. }
  4329.  
  4330. #------------------------------------------------------------------------------
  4331. # Function:        Format a date according to Message[78] (country date format)
  4332. # Parameters:   String date YYYYMMDDHHMMSS
  4333. #               Option 0=LastUpdate and LastTime date
  4334. #                      1=Arrays date except daymonthvalues
  4335. #                      2=daymonthvalues date (only year month and day)
  4336. # Input:        $Message[78]
  4337. # Output:       None
  4338. # Return:       Date with format defined by Message[78] and option
  4339. #------------------------------------------------------------------------------
  4340. sub Format_Date {
  4341.     my $date=shift;
  4342.     my $option=shift||0;
  4343.     my $year=substr("$date",0,4);
  4344.     my $month=substr("$date",4,2);
  4345.     my $day=substr("$date",6,2);
  4346.     my $hour=substr("$date",8,2);
  4347.     my $min=substr("$date",10,2);
  4348.     my $sec=substr("$date",12,2);
  4349.     my $dateformat=$Message[78];
  4350.     if ($option == 2) {
  4351.         $dateformat =~ s/^[^ymd]+//g;
  4352.         $dateformat =~ s/[^ymd]+$//g;
  4353.     }
  4354.     $dateformat =~ s/yyyy/$year/g;
  4355.     $dateformat =~ s/yy/$year/g;
  4356.     $dateformat =~ s/mmm/$MonthNumLib{$month}/g;
  4357.     $dateformat =~ s/mm/$month/g;
  4358.     $dateformat =~ s/dd/$day/g;
  4359.     $dateformat =~ s/HH/$hour/g;
  4360.     $dateformat =~ s/MM/$min/g;
  4361.     $dateformat =~ s/SS/$sec/g;
  4362.     return "$dateformat";
  4363. }
  4364.  
  4365. #------------------------------------------------------------------------------
  4366. # Function:     Return 1 if string contains only ascii chars
  4367. # Parameters:   string
  4368. # Input:        None
  4369. # Output:       None
  4370. # Return:       0 or 1
  4371. #------------------------------------------------------------------------------
  4372. sub IsAscii {
  4373.     my $string=shift;
  4374.     if ($Debug) { debug("IsAscii($string)",5); }
  4375.     if ($string =~ /^[\w\+\-\/\\\.%,;:=\"\'&?!\s]+$/) {
  4376.         if ($Debug) { debug(" Yes",6); }
  4377.         return 1;        # Only alphanum chars (and _) or + - / \ . % , ; : = " ' & ? space \t
  4378.     }
  4379.     if ($Debug) { debug(" No",6); }
  4380.     return 0;
  4381. }
  4382.  
  4383. #------------------------------------------------------------------------------
  4384. # Function:     Return the lower value between 2 but exclude value if 0
  4385. # Parameters:   Val1 and Val2
  4386. # Input:        None
  4387. # Output:       None
  4388. # Return:       min(Val1,Val2)
  4389. #------------------------------------------------------------------------------
  4390. sub MinimumButNoZero {
  4391.     my ($val1,$val2)=@_;
  4392.     return ($val1&&($val1<$val2||!$val2)?$val1:$val2);
  4393. }
  4394.  
  4395. #------------------------------------------------------------------------------
  4396. # Function:     Add a val from sorting tree
  4397. # Parameters:   keytoadd keyval [firstadd]
  4398. # Input:        None
  4399. # Output:       None
  4400. # Return:       None
  4401. #------------------------------------------------------------------------------
  4402. sub AddInTree {
  4403.     my $keytoadd=shift;
  4404.     my $keyval=shift;
  4405.     my $firstadd=shift||0;
  4406.     if ($firstadd==1) {            # Val is the first one
  4407.         if ($Debug) { debug("  firstadd",4); }
  4408.         $val{$keyval}=$keytoadd;
  4409.         $lowerval=$keyval;
  4410.         if ($Debug) { debug("  lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); }
  4411.         return;
  4412.     }
  4413.     if ($val{$keyval}) {         # Val is already in tree
  4414.         if ($Debug) { debug("  val is already in tree",4); }
  4415.         $egal{$keytoadd}=$val{$keyval};
  4416.         $val{$keyval}=$keytoadd;
  4417.         if ($Debug) { debug("  lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); }
  4418.         return;
  4419.     }
  4420.     if ($keyval <= $lowerval) {    # Val is a new one lower (should happens only when tree is not full)
  4421.         if ($Debug) { debug("  keytoadd val=$keyval is lower or equal to lowerval=$lowerval",4); }
  4422.         $val{$keyval}=$keytoadd;
  4423.         $nextval{$keyval}=$lowerval;
  4424.         $lowerval=$keyval;
  4425.         if ($Debug) { debug("  lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); }
  4426.         return;
  4427.     }
  4428.     # Val is a new one higher
  4429.     if ($Debug) { debug("  keytoadd val=$keyval is higher than lowerval=$lowerval",4); }
  4430.     $val{$keyval}=$keytoadd;
  4431.     my $valcursor=$lowerval;    # valcursor is value just before keyval
  4432.     while ($nextval{$valcursor} && ($nextval{$valcursor} < $keyval)) { $valcursor=$nextval{$valcursor}; }
  4433.     if ($nextval{$valcursor}) {    # keyval is between valcursor and nextval{valcursor}
  4434.         $nextval{$keyval}=$nextval{$valcursor};
  4435.     }
  4436.     $nextval{$valcursor}=$keyval;
  4437.     if ($Debug) { debug("  lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",4); }
  4438. }
  4439.  
  4440. #------------------------------------------------------------------------------
  4441. # Function:     Remove a val from sorting tree
  4442. # Parameters:   None
  4443. # Input:        $lowerval %val %egal
  4444. # Output:       None
  4445. # Return:       None
  4446. #------------------------------------------------------------------------------
  4447. sub Removelowerval {
  4448.     my $keytoremove=$val{$lowerval};    # This is lower key
  4449.     if ($Debug) { debug("   remove for lowerval=$lowerval: key=$keytoremove",4); }
  4450.     if ($egal{$keytoremove}) {
  4451.         $val{$lowerval}=$egal{$keytoremove};
  4452.         delete $egal{$keytoremove};
  4453.     }
  4454.     else {
  4455.         delete $val{$lowerval};
  4456.         $lowerval=$nextval{$lowerval};    # Set new lowerval
  4457.     }
  4458.     if ($Debug) { debug("   new lower value=$lowerval, val size=".(scalar keys %val).", egal size=".(scalar keys %egal),4); }
  4459. }
  4460.  
  4461. #------------------------------------------------------------------------------
  4462. # Function:     Build @keylist array
  4463. # Parameters:   Size max for @keylist array,
  4464. #               Min value in hash for select,
  4465. #               Hash used for select,
  4466. #               Hash used for order
  4467. # Input:        None
  4468. # Output:       None
  4469. # Return:       @keylist response array
  4470. #------------------------------------------------------------------------------
  4471. sub BuildKeyList {
  4472.     my $ArraySize=shift||error("System error. Call to BuildKeyList function with incorrect value for first param","","",1);
  4473.     my $MinValue=shift||error("System error. Call to BuildKeyList function with incorrect value for second param","","",1);
  4474.     my $hashforselect=shift;
  4475.     my $hashfororder=shift;
  4476.     if ($Debug) { debug(" BuildKeyList($ArraySize,$MinValue,$hashforselect with size=".(scalar keys %$hashforselect).",$hashfororder with size=".(scalar keys %$hashfororder).")",2); }
  4477.     delete $hashforselect->{0};delete $hashforselect->{''};        # Those is to protect from infinite loop when hash array has an incorrect null key
  4478.     my $count=0;
  4479.     $lowerval=0;    # Global because used in AddInTree and Removelowerval
  4480.     %val=(); %nextval=(); %egal=();
  4481.     foreach my $key (keys %$hashforselect) {
  4482.         if ($count < $ArraySize) {
  4483.             if ($hashforselect->{$key} >= $MinValue) {
  4484.                 $count++;
  4485.                 if ($Debug) { debug("  Add in tree entry $count : $key (value=".($hashfororder->{$key}||0).", tree not full)",4); }
  4486.                 AddInTree($key,$hashfororder->{$key}||0,$count);
  4487.             }
  4488.             next;
  4489.         }
  4490.         $count++;
  4491.         if (($hashfororder->{$key}||0)<=$lowerval) { next; }
  4492.         if ($Debug) { debug("  Add in tree entry $count : $key (value=".($hashfororder->{$key}||0)." > lowerval=$lowerval)",4); }
  4493.         AddInTree($key,$hashfororder->{$key}||0);
  4494.         if ($Debug) { debug("  Removelower in tree",4); }
  4495.         Removelowerval();
  4496.     }
  4497.  
  4498.     # Build key list and sort it
  4499.     if ($Debug) { debug("  Build key list and sort it. lowerval=$lowerval, nb elem val=".(scalar keys %val).", nb elem egal=".(scalar keys %egal).".",2); }
  4500.     my %notsortedkeylist=();
  4501.     foreach my $key (values %val) {    $notsortedkeylist{$key}=1; }
  4502.     foreach my $key (values %egal) { $notsortedkeylist{$key}=1; }
  4503.     @keylist=();
  4504.     @keylist=(sort {($hashfororder->{$b}||0) <=> ($hashfororder->{$a}||0) } keys %notsortedkeylist);
  4505.     if ($Debug) { debug(" BuildKeyList End (keylist size=".(@keylist).")",2); }
  4506.     return;
  4507. }
  4508.  
  4509. #------------------------------------------------------------------------------
  4510. # Function:     Lock or unlock update
  4511. # Parameters:   status (1 to lock, 0 to unlock)
  4512. # Input:        $DirLock (if status=0) $PROG $FileSuffix
  4513. # Output:       $DirLock (if status=1)
  4514. # Return:       None
  4515. #------------------------------------------------------------------------------
  4516. sub Lock_Update {
  4517.     my $status=shift;
  4518.     my $lock="$PROG$FileSuffix.lock";
  4519.     if ($status) {
  4520.         # We stop if there is at least one lock file wherever it is
  4521.         foreach my $key ($ENV{"TEMP"},$ENV{"TMP"},"/tmp","/",".") {
  4522.             my $newkey =$key;
  4523.             $newkey =~ s/[\\\/]$//;
  4524.             if (-f "$newkey/$lock") { error("An AWStats update process seems to be already running for this config file. Try later.\nIf this is not true, remove manually lock file '$newkey/$lock'.","","",1); }
  4525.         }
  4526.         # Set lock where we can
  4527.         foreach my $key ($ENV{"TEMP"},$ENV{"TMP"},"/tmp","/",".") {
  4528.             if (! -d "$key") { next; }
  4529.             $DirLock=$key;
  4530.             $DirLock =~ s/[\\\/]$//;
  4531.             if ($Debug) { debug("Update lock file $DirLock/$lock is set"); }
  4532.             open(LOCK,">$DirLock/$lock") || error("Failed to create lock file $DirLock/$lock","","",1);
  4533.             print LOCK "AWStats update started by process $$ at $nowyear-$nowmonth-$nowday $nowhour:$nowmin:$nowsec\n";
  4534.             close(LOCK);
  4535.             last;
  4536.         }
  4537.     }
  4538.     else {
  4539.         # Remove lock
  4540.         if ($Debug) { debug("Update lock file $DirLock/$lock is removed"); }
  4541.         unlink("$DirLock/$lock");
  4542.     }
  4543.     return;
  4544. }
  4545.  
  4546. #------------------------------------------------------------------------------
  4547. # Function:     Signal handler to call Lock_Update to remove lock file
  4548. # Parameters:   Signal name
  4549. # Input:        None
  4550. # Output:       None
  4551. # Return:       None
  4552. #------------------------------------------------------------------------------
  4553. sub SigHandler {
  4554.     my $signame = shift;
  4555.     print ucfirst($PROG)." process (ID $$) interrupted by signal $signame.\n";
  4556.     &Lock_Update(0);
  4557.     exit 1;
  4558. }
  4559.  
  4560. #------------------------------------------------------------------------------
  4561. # Function:     Convert an IPAddress into an integer
  4562. # Parameters:   IPAddress
  4563. # Input:        None
  4564. # Output:       None
  4565. # Return:       Int
  4566. #------------------------------------------------------------------------------
  4567. sub Convert_IP_To_Decimal {
  4568.     my ($IPAddress) = @_;
  4569.     my @ip_seg_arr = split(/\./,$IPAddress);
  4570.     my $decimal_ip_address = 256 * 256 *256 * $ip_seg_arr[0] + 256 * 256 * $ip_seg_arr[1] + 256 * $ip_seg_arr[2] + $ip_seg_arr[3];
  4571.     return($decimal_ip_address);
  4572. }
  4573.  
  4574. #------------------------------------------------------------------------------
  4575. # Function:     Test there is at least on value in list not null
  4576. # Parameters:   List of values
  4577. # Input:        None
  4578. # Output:       None
  4579. # Return:       1 There is at least one not null value, 0 else
  4580. #------------------------------------------------------------------------------
  4581. sub AtLeastOneNotNull {
  4582.     if ($Debug) { debug(" Call to AtLeastOneNotNull (".join('-',@_).")",3); }
  4583.     foreach my $val (@_) { if ($val) { return 1; } }
  4584.     return 0;
  4585. }
  4586.  
  4587. #------------------------------------------------------------------------------
  4588. # Function:     Return the string to add in html tag to include popup javascript code
  4589. # Parameters:   tooltip number
  4590. # Input:        None
  4591. # Output:       None
  4592. # Return:       string with javascript code
  4593. #------------------------------------------------------------------------------
  4594. sub Tooltip {
  4595.     my $ttnb=shift;
  4596.     return ($TOOLTIPON?" onmouseover=\"ShowTip($ttnb);\" onmouseout=\"HideTip($ttnb);\"":"");
  4597. }
  4598.  
  4599. #------------------------------------------------------------------------------
  4600. # Function:     Insert a form filter
  4601. # Parameters:   Name of filter field, default for filter field, default for exclude filter field
  4602. # Input:        $StaticLinks, $QueryString, $SiteConfig, $DirConfig
  4603. # Output:       HTML Form
  4604. # Return:       None
  4605. #------------------------------------------------------------------------------
  4606. sub ShowFormFilter {
  4607.     my $fieldfiltername=shift;
  4608.     my $fieldfilterinvalue=shift;
  4609.     my $fieldfilterexvalue=shift;
  4610.     if (! $StaticLinks) {
  4611.         my $NewLinkParams=${QueryString};
  4612.         $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  4613.         $NewLinkParams =~ s/(^|&)output(=\w*|$)//i;
  4614.         $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  4615.         $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  4616.         if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  4617.         print "\n<form name=\"FormFilter\" action=\"".XMLEncode("$AWScript?${NewLinkParams}")."\" class=\"aws_border\">\n";
  4618.         print "<table valign=\"middle\" width=\"99%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\"><tr>\n";
  4619.         print "<td align=\"left\" width=\"50\">$Message[79] :</td>\n";
  4620.         print "<td align=\"left\" width=\"100\"><input type=\"text\" name=\"${fieldfiltername}\" value=\"$fieldfilterinvalue\" class=\"aws_formfield\" /></td>\n";
  4621.         print "<td>   </td>";
  4622.         print "<td align=\"left\" width=\"100\">$Message[153] :</td>\n";
  4623.         print "<td align=\"left\" width=\"100\"><input type=\"text\" name=\"${fieldfiltername}ex\" value=\"$fieldfilterexvalue\" class=\"aws_formfield\" /></td>\n";
  4624.         print "<td>";
  4625.         print "<input type=\"hidden\" name=\"output\" value=\"".join(',',keys %HTMLOutput)."\" />\n";
  4626.         if ($SiteConfig) { print "<input type=\"hidden\" name=\"config\" value=\"$SiteConfig\" />\n"; }
  4627.          if ($DirConfig)  { print "<input type=\"hidden\" name=\"configdir\" value=\"$DirConfig\" />\n"; }
  4628.         if ($QueryString =~ /(^|&)year=(\d\d\d\d)/i) { print "<input type=\"hidden\" name=\"year\" value=\"$2\" />\n"; }
  4629.         if ($QueryString =~ /(^|&)month=(\d\d)/i || $QueryString =~ /(^|&)month=(all)/i) { print "<input type=\"hidden\" name=\"month\" value=\"$2\" />\n"; }
  4630.         if ($QueryString =~ /(^|&)lang=(\w+)/i) { print "<input type=\"hidden\" name=\"lang\" value=\"$2\" />\n"; }
  4631.         if ($QueryString =~ /(^|&)debug=(\d+)/i) { print "<input type=\"hidden\" name=\"debug\" value=\"$2\" />\n"; }
  4632.         if ($QueryString =~ /(^|&)framename=(\w+)/i) { print "<input type=\"hidden\" name=\"framename\" value=\"$2\" />\n"; }
  4633.         print "<input type=\"submit\" value=\" $Message[115] \" class=\"aws_button\" /></td>\n";
  4634.         print "<td>   </td>";
  4635.         print "</tr></table>\n";
  4636.         print "</form>\n";
  4637.         print "<br />\n";
  4638.         print "\n";
  4639.     }
  4640. }
  4641.  
  4642. #------------------------------------------------------------------------------
  4643. # Function:     Write other user info (with help of plugin)
  4644. # Parameters:   $user
  4645. # Input:        $SiteConfig
  4646. # Output:       URL link
  4647. # Return:       None
  4648. #------------------------------------------------------------------------------
  4649. sub ShowUserInfo {
  4650.     my $user=shift;
  4651.     # Call to plugins' function ShowInfoUser
  4652.     foreach my $pluginname (keys %{$PluginsLoaded{'ShowInfoUser'}})  {
  4653.         my $function="ShowInfoUser_$pluginname('$user')";
  4654.         eval("$function");
  4655.     }
  4656. }
  4657.  
  4658. #------------------------------------------------------------------------------
  4659. # Function:     Write other host info (with help of plugin)
  4660. # Parameters:   $host
  4661. # Input:        $LinksToWhoIs $LinksToWhoIsIp
  4662. # Output:       None
  4663. # Return:       None
  4664. #------------------------------------------------------------------------------
  4665. sub ShowHostInfo {
  4666.     my $host=shift;
  4667.     # Call to plugins' function ShowInfoHost
  4668.     foreach my $pluginname (keys %{$PluginsLoaded{'ShowInfoHost'}})  {
  4669.         my $function="ShowInfoHost_$pluginname('$host')";
  4670.         eval("$function");
  4671.     }
  4672. }
  4673.  
  4674. #------------------------------------------------------------------------------
  4675. # Function:     Write other url info (with help of plugin)
  4676. # Parameters:   $url
  4677. # Input:        %Aliases $MaxLengthOfShownURL $ShowLinksOnUrl $SiteDomain $UseHTTPSLinkForUrl
  4678. # Output:       URL link
  4679. # Return:       None
  4680. #------------------------------------------------------------------------------
  4681. sub ShowURLInfo {
  4682.     my $url=shift;
  4683.     my $nompage=CleanFromCSSA($url);
  4684.  
  4685.     # Call to plugins' function ShowInfoURL
  4686.     foreach my $pluginname (keys %{$PluginsLoaded{'ShowInfoURL'}})  {
  4687.         my $function="ShowInfoURL_$pluginname('$url')";
  4688.         eval("$function");
  4689.     }
  4690.  
  4691.     if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; }
  4692.     if ($ShowLinksOnUrl) {
  4693.         my $newkey=CleanFromCSSA($url);
  4694.         if ($LogType eq 'W' || $LogType eq 'S') {        # Web or streaming log file
  4695.             if ($newkey =~ /^http(s|):/i) {    # URL seems to be extracted from a proxy log file
  4696.                 print "<a href=\"".XMLEncode("$newkey")."\" target=\"url\">".XMLEncode($nompage)."</a>";
  4697.             }
  4698.             elsif ($newkey =~ /^\//) {        # URL seems to be an url extracted from a web or wap server log file
  4699.                 $newkey =~ s/^\/$SiteDomain//i;
  4700.                 # Define urlprot
  4701.                 my $urlprot='http';
  4702.                 if ($UseHTTPSLinkForUrl && $newkey =~ /^$UseHTTPSLinkForUrl/) { $urlprot='https'; }
  4703.                 print "<a href=\"".XMLEncode("$urlprot://$SiteDomain$newkey\"")." target=\"url\">".XMLEncode($nompage)."</a>";
  4704.             }
  4705.             else {
  4706.                 print XMLEncode($nompage);
  4707.             }
  4708.         }
  4709.         elsif ($LogType eq 'F') {    # Ftp log file
  4710.             print XMLEncode($nompage);
  4711.         }
  4712.         elsif ($LogType eq 'M') {    # Smtp log file
  4713.             print XMLEncode($nompage);
  4714.         }
  4715.         else {                        # Other type log file
  4716.             print XMLEncode($nompage);
  4717.         }
  4718.     }
  4719.     else {
  4720.         print XMLEncode($nompage);
  4721.     }
  4722. }
  4723.  
  4724. #------------------------------------------------------------------------------
  4725. # Function:     Define value for PerlParsingFormat (used for regex log record parsing)
  4726. # Parameters:   -
  4727. # Input:        $LogFormat
  4728. # Output:       @fieldlib
  4729. # Return:       -
  4730. #------------------------------------------------------------------------------
  4731. sub DefinePerlParsingFormat {
  4732.     # Log records examples:
  4733.     # Apache combined: 62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "GET / HTTP/1.1" 200 1234 "http://www.from.com/from.htm" "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"
  4734.     # Apache combined (408 error): my.domain.com - user [09/Jan/2001:11:38:51 -0600] "OPTIONS /mime-tmp/xxx file.doc HTTP/1.1" 408 - "-" "-"
  4735.     # Apache combined (408 error): 62.161.78.73 user - [dd/mmm/yyyy:hh:mm:ss +0000] "-" 408 - "-" "-"
  4736.     # Apache common_with_mod_gzip_info1: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct.
  4737.     # Apache common_with_mod_gzip_info2: %h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct.
  4738.     # Apache deflate: %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" (%{ratio}n)
  4739.     # IIS: 2000-07-19 14:14:14 62.161.78.73 - GET / 200 1234 HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+NT+5.0) http://www.from.com/from.htm
  4740.     # WebStar: 05/21/00    00:17:31    OK      200    212.242.30.6    Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)    http://www.cover.dk/    "www.cover.dk"    :Documentation:graphics:starninelogo.white.gif    1133
  4741.     # Squid extended: 12.229.91.170 - - [27/Jun/2002:03:30:50 -0700] "GET http://www.callistocms.com/images/printable.gif HTTP/1.1" 304 354 "-" "Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/0" TCP_REFRESH_HIT:DIRECT
  4742.     if ($Debug) { debug("Call To DefinePerlParsingFormat (LogType='$LogType', LogFormat='$LogFormat')"); }
  4743.     @fieldlib=();
  4744.     if ($LogFormat =~ /^[1-6]$/) {    # Pre-defined log format
  4745.         if ($LogFormat eq '1' || $LogFormat eq '6') {    # Same than "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"".
  4746.             # %u (user) is "([^\\[]+)" instead of "[^ ]+" because can contain space (Lotus Notes). referer and ua might be "".
  4747. #            $PerlParsingFormat="([^ ]+) [^ ]+ ([^\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) (.+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\"";
  4748.             $PerlParsingFormat="([^ ]+) [^ ]+ ([^\\[]+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+) \\\"(.*?)\\\" \\\"([^\\\"]*)\\\"";
  4749.             $pos_host=0;$pos_logname=1;$pos_date=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6;$pos_referer=7;$pos_agent=8;
  4750.             @fieldlib=('host','logname','date','method','url','code','size','referer','ua');
  4751.         }
  4752.         elsif ($LogFormat eq '2') {    # Same than "date time c-ip cs-username cs-method cs-uri-stem sc-status sc-bytes cs-version cs(User-Agent) cs(Referer)"
  4753.             $PerlParsingFormat="(\\S+ \\S+) (\\S+) (\\S+) (\\S+) (\\S+) ([\\d|-]+) ([\\d|-]+) \\S+ (\\S+) (\\S+)";
  4754.             $pos_date=0;$pos_host=1;$pos_logname=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6;$pos_agent=7;$pos_referer=8;
  4755.             @fieldlib=('date','host','logname','method','url','code','size','ua','referer');
  4756.         }
  4757.         elsif ($LogFormat eq '3') {
  4758.             $PerlParsingFormat="([^\\t]*\\t[^\\t]*)\\t([^\\t]*)\\t([\\d|-]*)\\t([^\\t]*)\\t([^\\t]*)\\t([^\\t]*)\\t[^\\t]*\\t([^\\t]*)\\t([\\d]*)";
  4759.             $pos_date=0;$pos_method=1;$pos_code=2;$pos_host=3;$pos_agent=4;$pos_referer=5;$pos_url=6;$pos_size=7;
  4760.             @fieldlib=('date','method','code','host','ua','referer','url','size');
  4761.         }
  4762.         elsif ($LogFormat eq '4') {    # Same than "%h %l %u %t \"%r\" %>s %b"
  4763.             # %u (user) is "(.+)" instead of "[^ ]+" because can contain space (Lotus Notes).
  4764.             $PerlParsingFormat="([^ ]+) [^ ]+ (.+) \\[([^ ]+) [^ ]+\\] \\\"([^ ]+) ([^ ]+) [^\\\"]+\\\" ([\\d|-]+) ([\\d|-]+)";
  4765.             $pos_host=0;$pos_logname=1;$pos_date=2;$pos_method=3;$pos_url=4;$pos_code=5;$pos_size=6;
  4766.             @fieldlib=('host','logname','date','method','url','code','size');
  4767.         }
  4768.         # This is a deprecated option, will be removed in a next version.
  4769.         elsif ($LogFormat eq '5') {    # Same than "c-ip cs-username c-agent sc-authenticated date time s-svcname s-computername cs-referred r-host r-ip r-port time-taken cs-bytes sc-bytes cs-protocol cs-transport s-operation cs-uri cs-mime-type s-object-source sc-status s-cache-info"
  4770.             $PerlParsingFormat="([^\\t]*)\\t([^\\t]*)\\t([^\\t]*)\\t[^\\t]*\\t([^\\t]*\\t[^\\t]*)\\t[^\\t]*\\t[^\\t]*\\t([^\\t]*)\\t[^\\t]*\\t[^\\t]*\\t[^\\t]*\\t[^\\t]*\\t[^\\t]*\\t([^\\t]*)\\t[^\\t]*\\t[^\\t]*\\t([^\\t]*)\\t([^\\t]*)\\t[^\\t]*\\t[^\\t]*\\t([^\\t]*)\\t[^\\t]*";
  4771.             $pos_host=0;$pos_logname=1;$pos_agent=2;$pos_date=3;$pos_referer=4;$pos_size=5;$pos_method=6;$pos_url=7;$pos_code=8;
  4772.             @fieldlib=('host','logname','ua','date','referer','size','method','url','code');
  4773.         }
  4774.     }
  4775.     else {                            # Personalized log format
  4776.         my $LogFormatString=$LogFormat;
  4777.         # Replacement for Notes format string that are not Apache
  4778.         $LogFormatString =~ s/%vh/%virtualname/g;
  4779.         # Replacement for Apache format string
  4780.         $LogFormatString =~ s/%v(\s)/%virtualname$1/g; $LogFormatString =~ s/%v$/%virtualname/g;
  4781.         $LogFormatString =~ s/%h(\s)/%host$1/g; $LogFormatString =~ s/%h$/%host/g;
  4782.         $LogFormatString =~ s/%l(\s)/%other$1/g; $LogFormatString =~ s/%l$/%other/g;
  4783.         $LogFormatString =~ s/\"%u\"/%lognamequot/g;
  4784.         $LogFormatString =~ s/%u(\s)/%logname$1/g; $LogFormatString =~ s/%u$/%logname/g;
  4785.         $LogFormatString =~ s/%t(\s)/%time1$1/g; $LogFormatString =~ s/%t$/%time1/g;
  4786.         $LogFormatString =~ s/\"%r\"/%methodurl/g;
  4787.         $LogFormatString =~ s/%>s/%code/g;
  4788.         $LogFormatString =~ s/%b(\s)/%bytesd$1/g;    $LogFormatString =~ s/%b$/%bytesd/g;
  4789.         $LogFormatString =~ s/\"%{Referer}i\"/%refererquot/g;
  4790.         $LogFormatString =~ s/\"%{User-Agent}i\"/%uaquot/g;
  4791.         $LogFormatString =~ s/%{mod_gzip_input_size}n/%gzipin/g;
  4792.         $LogFormatString =~ s/%{mod_gzip_output_size}n/%gzipout/g;
  4793.         $LogFormatString =~ s/%{mod_gzip_compression_ratio}n/%gzipratio/g;
  4794.         $LogFormatString =~ s/\(%{ratio}n\)/%deflateratio/g;
  4795.         # Replacement for a IIS and ISA format string
  4796.         $LogFormatString =~ s/cs-uri-query/%query/g;    # Must be before cs-uri
  4797.         $LogFormatString =~ s/date\stime/%time2/g;
  4798.         $LogFormatString =~ s/c-ip/%host/g;
  4799.         $LogFormatString =~ s/cs-username/%logname/g;
  4800.         $LogFormatString =~ s/cs-method/%method/g;        # GET, POST, SMTP, RETR STOR
  4801.         $LogFormatString =~ s/cs-uri-stem/%url/g; $LogFormatString =~ s/cs-uri/%url/g;
  4802.         $LogFormatString =~ s/sc-status/%code/g;
  4803.         $LogFormatString =~ s/sc-bytes/%bytesd/g;
  4804.         $LogFormatString =~ s/cs-version/%other/g;        # Protocol
  4805.         $LogFormatString =~ s/cs\(User-Agent\)/%ua/g; $LogFormatString =~ s/c-agent/%ua/g;
  4806.         $LogFormatString =~ s/cs\(Referer\)/%referer/g; $LogFormatString =~ s/cs-referred/%referer/g;
  4807.         $LogFormatString =~ s/sc-authenticated/%other/g;
  4808.         $LogFormatString =~ s/s-svcname/%other/g;
  4809.         $LogFormatString =~ s/s-computername/%other/g;
  4810.         $LogFormatString =~ s/r-host/%virtualname/g;
  4811.         $LogFormatString =~ s/r-ip/%other/g;
  4812.         $LogFormatString =~ s/r-port/%other/g;
  4813.         $LogFormatString =~ s/time-taken/%other/g;
  4814.         $LogFormatString =~ s/cs-bytes/%other/g;
  4815.         $LogFormatString =~ s/cs-protocol/%other/g;
  4816.         $LogFormatString =~ s/cs-transport/%other/g;
  4817.         $LogFormatString =~ s/s-operation/%method/g;    # GET, POST, SMTP, RETR STOR
  4818.         $LogFormatString =~ s/cs-mime-type/%other/g;
  4819.         $LogFormatString =~ s/s-object-source/%other/g;
  4820.         $LogFormatString =~ s/s-cache-info/%other/g;
  4821.         # Added for MMS
  4822.         $LogFormatString =~ s/protocol/%protocolmms/g;    # cs-method might not be available
  4823.         $LogFormatString =~ s/c-status/%codemms/g;        # c-status used when sc-status not available
  4824.         if ($Debug) { debug(" LogFormatString=$LogFormatString"); }
  4825.         # $LogFormatString has an AWStats format, so we can generate PerlParsingFormat variable
  4826.         my $i = 0;
  4827.         my $LogSeparatorWithoutStar=$LogSeparator; $LogSeparatorWithoutStar =~ s/[\*\+]//g;
  4828.         foreach my $f (split(/\s+/,$LogFormatString)) {
  4829.             # Add separator for next field
  4830.             if ($PerlParsingFormat) { $PerlParsingFormat.="$LogSeparator"; }
  4831.             # Special for logname
  4832.             if ($f =~ /%lognamequot$/) {
  4833.                 $pos_logname = $i; $i++; push @fieldlib, 'logname';
  4834.                 $PerlParsingFormat .= "\\\"?([^\\\"]*)\\\"?";            # logname can be "value", "" and - in same log (Lotus notes)
  4835.             }
  4836.             # Date format
  4837.             elsif ($f =~ /%time1$/ || $f =~ /%time1b$/) {    # [dd/mmm/yyyy:hh:mm:ss +0000] ou [dd/mmm/yyyy:hh:mm:ss],  time1b kept for backward compatibility
  4838.                 $pos_date = $i;    $i++; push @fieldlib, 'date';
  4839.                 $pos_tz = $i; $i++; push @fieldlib, 'tz';
  4840.                 $PerlParsingFormat .= "\\[([^$LogSeparatorWithoutStar]+)( [^$LogSeparatorWithoutStar]+)?\\]";
  4841.             }
  4842.             elsif ($f =~ /%time2$/) {    # yyyy-mm-dd hh:mm:ss
  4843.                 $pos_date = $i;    $i++; push @fieldlib, 'date';
  4844.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+\\s[^$LogSeparatorWithoutStar]+)";    # Need \s for Exchange log files
  4845.             }
  4846.             elsif ($f =~ /%time3$/) {    # mon d hh:mm:ss
  4847.                 $pos_date = $i;    $i++; push @fieldlib, 'date';
  4848.                 $PerlParsingFormat .= "(\\w\\w\\w \\s??\\d+ \\d\\d:\\d\\d:\\d\\d)";
  4849.             }
  4850.             elsif ($f =~ /%time4$/) {    # ddddddddddddd
  4851.                 $pos_date = $i;    $i++; push @fieldlib, 'date';
  4852.                 $PerlParsingFormat .= "(\\d+)";
  4853.             }
  4854.             # Special for methodurl and methodurlnoprot
  4855.             elsif ($f =~ /%methodurl$/) {
  4856.                 $pos_method = $i; $i++; push @fieldlib, 'method';
  4857.                 $pos_url = $i; $i++; push @fieldlib, 'url';
  4858.                 $PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+) [^\\\"]+\\\"";
  4859.             }
  4860.             elsif ($f =~ /%methodurlnoprot$/) {
  4861.                 $pos_method = $i; $i++; push @fieldlib, 'method';
  4862.                 $pos_url = $i; $i++; push @fieldlib, 'url';
  4863.                 $PerlParsingFormat .= "\\\"([^$LogSeparatorWithoutStar]+) ([^$LogSeparatorWithoutStar]+)\\\"";
  4864.             }
  4865.             # Common command tags
  4866.             elsif ($f =~ /%virtualname$/) {
  4867.                 $pos_vh = $i; $i++; push @fieldlib, 'vhost';
  4868.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4869.             }
  4870.             elsif ($f =~ /%host_r$/) {
  4871.                 $pos_hostr = $i; $i++; push @fieldlib, 'hostr';
  4872.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4873.             }
  4874.             elsif ($f =~ /%host$/) {
  4875.                 $pos_host = $i; $i++; push @fieldlib, 'host';
  4876.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4877.             }
  4878.             elsif ($f =~ /%logname$/) {
  4879.                 $pos_logname = $i; $i++; push @fieldlib, 'logname';
  4880.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4881.             }
  4882.             elsif ($f =~ /%method$/) {
  4883.                 $pos_method = $i; $i++; push @fieldlib, 'method';
  4884.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4885.             }
  4886.             elsif ($f =~ /%url$/) {
  4887.                 $pos_url = $i; $i++; push @fieldlib, 'url';
  4888.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4889.             }
  4890.             elsif ($f =~ /%query$/) {
  4891.                 $pos_query = $i; $i++; push @fieldlib, 'query';
  4892.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4893.             }
  4894.             elsif ($f =~ /%code$/) {
  4895.                 $pos_code = $i; $i++; push @fieldlib, 'code';
  4896.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4897.             }
  4898.             elsif ($f =~ /%bytesd$/) {
  4899.                 $pos_size = $i; $i++; push @fieldlib, 'size';
  4900.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4901.             }
  4902.             elsif ($f =~ /%refererquot$/) {
  4903.                 $pos_referer = $i; $i++; push @fieldlib, 'referer';
  4904.                 $PerlParsingFormat .= "\\\"([^\\\"]*)\\\"";         # referer might be ""
  4905.             }
  4906.             elsif ($f =~ /%referer$/) {
  4907.                 $pos_referer = $i; $i++; push @fieldlib, 'referer';
  4908.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4909.             }
  4910.             elsif ($f =~ /%uaquot$/) {
  4911.                 $pos_agent = $i; $i++; push @fieldlib, 'ua';
  4912.                 $PerlParsingFormat .= "\\\"([^\\\"]*)\\\"";            # ua might be ""
  4913.             }
  4914.             elsif ($f =~ /%uabracket$/) {
  4915.                 $pos_agent = $i; $i++; push @fieldlib, 'ua';
  4916.                 $PerlParsingFormat .= "\\\[([^\\\]]*)\\\]";         # ua might be []
  4917.             }
  4918.             elsif ($f =~ /%ua$/) {
  4919.                 $pos_agent = $i; $i++; push @fieldlib, 'ua';
  4920.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4921.             }
  4922.             elsif ($f =~ /%gzipin$/ ) {
  4923.                 $pos_gzipin=$i;$i++; push @fieldlib, 'gzipin';
  4924.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4925.             }
  4926.             elsif ($f =~ /%gzipout/ ) {        # Compare $f to /%gzipout/ and not to /%gzipout$/ like other fields
  4927.                 $pos_gzipout=$i;$i++; push @fieldlib, 'gzipout';
  4928.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4929.             }
  4930.             elsif ($f =~ /%gzipratio/ ) {    # Compare $f to /%gzipratio/ and not to /%gzipratio$/ like other fields
  4931.                 $pos_compratio=$i;$i++; push @fieldlib, 'gzipratio';
  4932.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4933.             }
  4934.             elsif ($f =~ /%deflateratio/ ) {    # Compare $f to /%deflateratio/ and not to /%deflateratio$/ like other fields
  4935.                 $pos_compratio=$i;$i++; push @fieldlib, 'deflateratio';
  4936.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4937.             }
  4938.             elsif ($f =~ /%email_r$/) {
  4939.                 $pos_emailr = $i; $i++; push @fieldlib, 'email_r';
  4940.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4941.             }
  4942.             elsif ($f =~ /%email$/) {
  4943.                 $pos_emails = $i; $i++; push @fieldlib, 'email';
  4944.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4945.             }
  4946.             elsif ($f =~ /%cluster$/) {
  4947.                 $pos_cluster = $i; $i++; push @fieldlib, 'clusternb';
  4948.                 $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4949.             }
  4950.             # Special for protocolmms, used for method if method not already found (for MMS)
  4951.             elsif ($f =~ /%protocolmms$/) {
  4952.                 if ($pos_method < 0) {
  4953.                     $pos_method = $i; $i++; push @fieldlib, 'method';
  4954.                     $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4955.                 }
  4956.             }
  4957.             # Special for codemms, used for code only if code not already found (for MMS)
  4958.             elsif ($f =~ /%codemms$/) {
  4959.                 if ($pos_code < 0) {
  4960.                     $pos_code = $i; $i++; push @fieldlib, 'code';
  4961.                     $PerlParsingFormat .= "([^$LogSeparatorWithoutStar]+)";
  4962.                 }
  4963.             }
  4964.             # Other tag
  4965.             elsif ($f =~ /%other$/) {
  4966.                 $PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+";
  4967.             }
  4968.             elsif ($f =~ /%otherquot$/) {
  4969.                 $PerlParsingFormat .= "\\\"[^\\\"]*\\\"";
  4970.             }
  4971.             # Unknown tag (no parenthesis)
  4972.             else {
  4973.                 $PerlParsingFormat .= "[^$LogSeparatorWithoutStar]+";
  4974.             }
  4975.         }
  4976.         if (! $PerlParsingFormat) { error("No recognized format tag in personalized LogFormat string"); }
  4977.     }
  4978.     if ($pos_host < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%host in your LogFormat string)."); }
  4979.     if ($pos_date < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%time1 or \%time2 in your LogFormat string)."); }
  4980.     if ($pos_method < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%method in your LogFormat string)."); }
  4981.     if ($pos_url < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%methodurl or \%url in your LogFormat string)."); }
  4982.     if ($pos_code < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%code in your LogFormat string)."); }
  4983.     if ($pos_size < 0) { error("Your personalized LogFormat does not include all fields required by AWStats (Add \%bytesd in your LogFormat string)."); }
  4984.     $PerlParsingFormat=qr/^$PerlParsingFormat/;
  4985.     if ($Debug) { debug(" PerlParsingFormat is $PerlParsingFormat"); }
  4986. }
  4987.  
  4988.  
  4989. sub ShowEmailSendersChart {
  4990.     my $NewLinkParams=shift;
  4991.     my $NewLinkTarget=shift;
  4992.     my $MaxLengthOfShownEMail=48;
  4993.  
  4994.     my $total_p;my $total_h;my $total_k;
  4995.     my $max_p;my $max_h;my $max_k;
  4996.     my $rest_p;my $rest_h;my $rest_k;
  4997.  
  4998.     # Show filter form
  4999.     #&ShowFormFilter("emailsfilter",$EmailsFilter);
  5000.     # Show emails list
  5001.  
  5002.     print "$Center<a name=\"emailsenders\"> </a><br />\n";
  5003.     my $title;
  5004.     if ($HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) {
  5005.         $title="$Message[131]";
  5006.     }
  5007.     else {
  5008.         $title="$Message[131] ($Message[77] $MaxNbOf{'EMailsShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allemails"):"$PROG$StaticLinks.allemails.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>";
  5009.         if ($ShowEMailSenders =~ /L/i) { $title.="   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastemails"):"$PROG$StaticLinks.lastemails.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>"; }
  5010.     }
  5011.     &tab_head("$title",19,0,'emailsenders');
  5012.     print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"3\">$Message[131] : ".(scalar keys %_emails_h)."</th>";
  5013.     if ($ShowEMailSenders =~ /H/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th>"; }
  5014.     if ($ShowEMailSenders =~ /B/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th>"; }
  5015.     if ($ShowEMailSenders =~ /M/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_k\" width=\"80\">$Message[106]</th>"; }
  5016.     if ($ShowEMailSenders =~ /L/i) { print "<th rowspan=\"2\" width=\"120\">$Message[9]</th>"; }
  5017.     print "</tr>\n";
  5018.     print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"30%\">Local</th><th> </th><th width=\"30%\">External</th></tr>";
  5019.     $total_p=$total_h=$total_k=0;
  5020.     $max_h=1; foreach (values %_emails_h) { if ($_ > $max_h) { $max_h = $_; } }
  5021.     $max_k=1; foreach (values %_emails_k) { if ($_ > $max_k) { $max_k = $_; } }
  5022.     my $count=0;
  5023.     if (! $HTMLOutput{'allemails'} && ! $HTMLOutput{'lastemails'}) { &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emails_h,\%_emails_h); }
  5024.     if ($HTMLOutput{'allemails'})  { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emails_h,\%_emails_h); }
  5025.     if ($HTMLOutput{'lastemails'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emails_h,\%_emails_l); }
  5026.     foreach my $key (@keylist) {
  5027.         my $newkey=$key;
  5028.         if (length($key)>$MaxLengthOfShownEMail) { $newkey=substr($key,0,$MaxLengthOfShownEMail)."..."; }
  5029.         my $bredde_h=0;my $bredde_k=0;
  5030.         if ($max_h > 0) { $bredde_h=int($BarWidth*$_emails_h{$key}/$max_h)+1; }
  5031.         if ($max_k > 0) { $bredde_k=int($BarWidth*$_emails_k{$key}/$max_k)+1; }
  5032.         print "<tr>";
  5033.         my $direction=IsLocalEMail($key);
  5034.         if ($direction > 0) { print "<td class=\"aws\">$newkey</td><td>-></td><td> </td>"; }
  5035.         if ($direction == 0) { print "<td colspan=\"3\"><span style=\"color: #$color_other\">$newkey</span></td>"; }
  5036.         if ($direction < 0) { print "<td class=\"aws\"> </td><td><-</td><td>$newkey</td>"; }
  5037.         if ($ShowEMailSenders =~ /H/i) { print "<td>$_emails_h{$key}</td>"; }
  5038.         if ($ShowEMailSenders =~ /B/i) { print "<td>".Format_Bytes($_emails_k{$key})."</td>"; }
  5039.         if ($ShowEMailSenders =~ /M/i) { print "<td>".Format_Bytes($_emails_k{$key}/($_emails_h{$key}||1))."</td>"; }
  5040.         if ($ShowEMailSenders =~ /L/i) { print "<td>".($_emails_l{$key}?Format_Date($_emails_l{$key},1):'-')."</td>"; }
  5041.         print "</tr>\n";
  5042.         #$total_p += $_emails_p{$key};
  5043.         $total_h += $_emails_h{$key};
  5044.         $total_k += $_emails_k{$key};
  5045.         $count++;
  5046.     }
  5047.     $rest_p=0;    # $rest_p=$TotalPages-$total_p;
  5048.     $rest_h=$TotalHits-$total_h;
  5049.     $rest_k=$TotalBytes-$total_k;
  5050.     if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other sender emails
  5051.         print "<tr><td colspan=\"3\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  5052.         if ($ShowEMailSenders =~ /H/i) { print "<td>$rest_h</td>"; }
  5053.         if ($ShowEMailSenders =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  5054.         if ($ShowEMailSenders =~ /M/i) { print "<td>".Format_Bytes($rest_k/($rest_h||1))."</td>"; }
  5055.         if ($ShowEMailSenders =~ /L/i) { print "<td> </td>"; }
  5056.         print "</tr>\n";
  5057.     }
  5058.     &tab_end();
  5059. }
  5060.  
  5061.  
  5062. sub ShowEmailReceiversChart {
  5063.     my $NewLinkParams=shift;
  5064.     my $NewLinkTarget=shift;
  5065.     my $MaxLengthOfShownEMail=48;
  5066.  
  5067.     my $total_p;my $total_h;my $total_k;
  5068.     my $max_p;my $max_h;my $max_k;
  5069.     my $rest_p;my $rest_h;my $rest_k;
  5070.  
  5071.     # Show filter form
  5072.     #&ShowFormFilter("emailrfilter",$EmailrFilter);
  5073.     # Show emails list
  5074.  
  5075.     print "$Center<a name=\"emailreceivers\"> </a><br />\n";
  5076.     my $title;
  5077.     if ($HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) {
  5078.         $title="$Message[132]";
  5079.     }
  5080.     else {
  5081.         $title="$Message[132] ($Message[77] $MaxNbOf{'EMailsShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allemailr"):"$PROG$StaticLinks.allemailr.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>";
  5082.         if ($ShowEMailReceivers =~ /L/i) { $title.="   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastemailr"):"$PROG$StaticLinks.lastemailr.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>"; }
  5083.     }
  5084.     &tab_head("$title",19,0,'emailreceivers');
  5085.     print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"3\">$Message[132] : ".(scalar keys %_emailr_h)."</th>";
  5086.     if ($ShowEMailReceivers =~ /H/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th>"; }
  5087.     if ($ShowEMailReceivers =~ /B/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th>"; }
  5088.     if ($ShowEMailReceivers =~ /M/i) { print "<th rowspan=\"2\" bgcolor=\"#$color_k\" width=\"80\">$Message[106]</th>"; }
  5089.     if ($ShowEMailReceivers =~ /L/i) { print "<th rowspan=\"2\" width=\"120\">$Message[9]</th>"; }
  5090.     print "</tr>\n";
  5091.     print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"30%\">Local</th><th> </th><th width=\"30%\">External</th></tr>";
  5092.     $total_p=$total_h=$total_k=0;
  5093.     $max_h=1; foreach (values %_emailr_h) { if ($_ > $max_h) { $max_h = $_; } }
  5094.     $max_k=1; foreach (values %_emailr_k) { if ($_ > $max_k) { $max_k = $_; } }
  5095.     my $count=0;
  5096.     if (! $HTMLOutput{'allemailr'} && ! $HTMLOutput{'lastemailr'}) { &BuildKeyList($MaxNbOf{'EMailsShown'},$MinHit{'EMail'},\%_emailr_h,\%_emailr_h); }
  5097.     if ($HTMLOutput{'allemailr'})  { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emailr_h,\%_emailr_h); }
  5098.     if ($HTMLOutput{'lastemailr'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'EMail'},\%_emailr_h,\%_emailr_l); }
  5099.     foreach my $key (@keylist) {
  5100.         my $newkey=$key;
  5101.         if (length($key)>$MaxLengthOfShownEMail) { $newkey=substr($key,0,$MaxLengthOfShownEMail)."..."; }
  5102.         my $bredde_h=0;my $bredde_k=0;
  5103.         if ($max_h > 0) { $bredde_h=int($BarWidth*$_emailr_h{$key}/$max_h)+1; }
  5104.         if ($max_k > 0) { $bredde_k=int($BarWidth*$_emailr_k{$key}/$max_k)+1; }
  5105.         print "<tr>";
  5106.         my $direction=IsLocalEMail($key);
  5107.         if ($direction > 0) { print "<td class=\"aws\">$newkey</td><td><-</td><td> </td>"; }
  5108.         if ($direction == 0) { print "<td colspan=\"3\"><span style=\"color: #$color_other\">$newkey</span></td>"; }
  5109.         if ($direction < 0) { print "<td class=\"aws\"> </td><td>-></td><td>$newkey</td>"; }
  5110.         if ($ShowEMailReceivers =~ /H/i) { print "<td>$_emailr_h{$key}</td>"; }
  5111.         if ($ShowEMailReceivers =~ /B/i) { print "<td>".Format_Bytes($_emailr_k{$key})."</td>"; }
  5112.         if ($ShowEMailReceivers =~ /M/i) { print "<td>".Format_Bytes($_emailr_k{$key}/($_emailr_h{$key}||1))."</td>"; }
  5113.         if ($ShowEMailReceivers =~ /L/i) { print "<td>".($_emailr_l{$key}?Format_Date($_emailr_l{$key},1):'-')."</td>"; }
  5114.         print "</tr>\n";
  5115.         #$total_p += $_emailr_p{$key};
  5116.         $total_h += $_emailr_h{$key};
  5117.         $total_k += $_emailr_k{$key};
  5118.         $count++;
  5119.     }
  5120.     $rest_p=0;    # $rest_p=$TotalPages-$total_p;
  5121.     $rest_h=$TotalHits-$total_h;
  5122.     $rest_k=$TotalBytes-$total_k;
  5123.     if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other receiver emails
  5124.         print "<tr><td colspan=\"3\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  5125.         if ($ShowEMailReceivers =~ /H/i) { print "<td>$rest_h</td>"; }
  5126.         if ($ShowEMailReceivers =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  5127.         if ($ShowEMailReceivers =~ /M/i) { print "<td>".Format_Bytes($rest_k/($rest_h||1))."</td>"; }
  5128.         if ($ShowEMailReceivers =~ /L/i) { print "<td> </td>"; }
  5129.         print "</tr>\n";
  5130.     }
  5131.     &tab_end();
  5132. }
  5133.  
  5134.  
  5135.  
  5136. #------------------------------------------------------------------------------
  5137. # MAIN
  5138. #------------------------------------------------------------------------------
  5139. ($DIR=$0) =~ s/([^\/\\]+)$//; ($PROG=$1) =~ s/\.([^\.]*)$//; $Extension=$1;
  5140. $DIR||='.'; $DIR =~ s/([^\/\\])[\\\/]+$/$1/;
  5141.  
  5142. $starttime=time();
  5143.  
  5144. # Get current time (time when AWStats was started)
  5145. ($nowsec,$nowmin,$nowhour,$nowday,$nowmonth,$nowyear,$nowwday,$nowyday) = localtime($starttime);
  5146. $nowweekofmonth=int($nowday/7);
  5147. $nowweekofyear=int(($nowyday-1+6-($nowwday==0?6:$nowwday-1))/7)+1; if ($nowweekofyear > 52) { $nowweekofyear = 1; }
  5148. $nowdaymod=$nowday%7;
  5149. $nowwday++;
  5150. $nowns=Time::Local::timegm(0,0,0,$nowday,$nowmonth,$nowyear);
  5151. if ($nowdaymod <= $nowwday) { if (($nowwday != 7) || ($nowdaymod != 0)) { $nowweekofmonth=$nowweekofmonth+1; } }
  5152. if ($nowdaymod >  $nowwday) { $nowweekofmonth=$nowweekofmonth+2; }
  5153. # Change format of time variables
  5154. $nowweekofmonth="0$nowweekofmonth";
  5155. if ($nowweekofyear < 10) { $nowweekofyear = "0$nowweekofyear"; }
  5156. if ($nowyear < 100) { $nowyear+=2000; } else { $nowyear+=1900; }
  5157. $nowsmallyear=$nowyear;$nowsmallyear =~ s/^..//;
  5158. if (++$nowmonth < 10) { $nowmonth = "0$nowmonth"; }
  5159. if ($nowday < 10) { $nowday = "0$nowday"; }
  5160. if ($nowhour < 10) { $nowhour = "0$nowhour"; }
  5161. if ($nowmin < 10) { $nowmin = "0$nowmin"; }
  5162. if ($nowsec < 10) { $nowsec = "0$nowsec"; }
  5163. $nowtime=int($nowyear.$nowmonth.$nowday.$nowhour.$nowmin.$nowsec);
  5164. # Get tomorrow time (will be used to discard some record with corrupted date (future date))
  5165. my ($tomorrowsec,$tomorrowmin,$tomorrowhour,$tomorrowday,$tomorrowmonth,$tomorrowyear) = localtime($starttime+86400);
  5166. if ($tomorrowyear < 100) { $tomorrowyear+=2000; } else { $tomorrowyear+=1900; }
  5167. if (++$tomorrowmonth < 10) { $tomorrowmonth = "0$tomorrowmonth"; }
  5168. if ($tomorrowday < 10) { $tomorrowday = "0$tomorrowday"; }
  5169. if ($tomorrowhour < 10) { $tomorrowhour = "0$tomorrowhour"; }
  5170. if ($tomorrowmin < 10) { $tomorrowmin = "0$tomorrowmin"; }
  5171. if ($tomorrowsec < 10) { $tomorrowsec = "0$tomorrowsec"; }
  5172. $tomorrowtime=int($tomorrowyear.$tomorrowmonth.$tomorrowday.$tomorrowhour.$tomorrowmin.$tomorrowsec);
  5173.  
  5174. # Allowed option
  5175. my @AllowedCLIArgs=('migrate','config',
  5176. 'logfile','output','runascli','update',
  5177. 'staticlinks','staticlinksext','noloadplugin','loadplugin',
  5178. 'hostfilter','urlfilter','refererpagesfilter',
  5179. 'lang','month','year','framename','debug',
  5180. 'showsteps','showdropped','showcorrupted','showunknownorigin',
  5181. 'limitflush','confdir','updatefor',
  5182. 'hostfilter','hostfilterex','urlfilter','urlfilterex','refererpagesfilter','refererpagesfilterex',
  5183. 'pluginmode','filterrawlog');
  5184.  
  5185. $QueryString='';
  5186. # AWStats use GATEWAY_INTERFACE to known if ran as CLI or CGI. AWSTATS_DEL_GATEWAY_INTERFACE can
  5187. # be set to force AWStats to be ran as CLI even from a web page.
  5188. if ($ENV{'AWSTATS_DEL_GATEWAY_INTERFACE'}) { $ENV{'GATEWAY_INTERFACE'}=''; }
  5189. if ($ENV{'GATEWAY_INTERFACE'}) {    # Run from a browser as CGI
  5190.     # Prepare QueryString
  5191.     if ($ENV{'CONTENT_LENGTH'}) {
  5192.         binmode STDIN;
  5193.         read(STDIN, $QueryString, $ENV{'CONTENT_LENGTH'});
  5194.     }
  5195.     if ($ENV{'QUERY_STRING'}) { $QueryString = $ENV{'QUERY_STRING'}; }
  5196.  
  5197.     $QueryString = CleanFromCSSA($QueryString);
  5198.     # No update but report by default when run from a browser
  5199.     $UpdateStats=($QueryString=~/update=1/i?1:0);
  5200.  
  5201.     if ($QueryString =~ /config=([^&]+)/i)                { $SiteConfig=&DecodeEncodedString("$1"); }
  5202.     if ($QueryString =~ /logfile=([^&]+)/i)                { $LogFile=&DecodeEncodedString("$1"); }
  5203.     if ($QueryString =~ /diricons=([^&]+)/i)            { $DirIcons=&DecodeEncodedString("$1"); }
  5204.     if ($QueryString =~ /pluginmode=([^&]+)/i)            { $PluginMode=&DecodeEncodedString("$1"); }
  5205.     if ($QueryString =~ /configdir=([^&]+)/i)            { $DirConfig=&DecodeEncodedString("$1"); }
  5206.     # All filters
  5207.     if ($QueryString =~ /hostfilter=([^&]+)/i)            { $FilterIn{'host'}=&DecodeEncodedString("$1"); }            # Filter on host list can also be defined with hostfilter=filter
  5208.     if ($QueryString =~ /hostfilterex=([^&]+)/i)        { $FilterEx{'host'}=&DecodeEncodedString("$1"); }            #
  5209.     if ($QueryString =~ /urlfilter=([^&]+)/i)            { $FilterIn{'url'}=&DecodeEncodedString("$1"); }            # Filter on URL list can also be defined with urlfilter=filter
  5210.     if ($QueryString =~ /urlfilterex=([^&]+)/i)            { $FilterEx{'url'}=&DecodeEncodedString("$1"); }            #
  5211.     if ($QueryString =~ /refererpagesfilter=([^&]+)/i)    { $FilterIn{'refererpages'}=&DecodeEncodedString("$1"); }    # Filter on referer list can also be defined with refererpagesfilter=filter
  5212.     if ($QueryString =~ /refererpagesfilterex=([^&]+)/i) { $FilterEx{'refererpages'}=&DecodeEncodedString("$1"); }    #
  5213.     # All output
  5214.     if ($QueryString =~ /output=allhosts:([^&]+)/i)        { $FilterIn{'host'}=&DecodeEncodedString("$1"); }            # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed
  5215.     if ($QueryString =~ /output=lasthosts:([^&]+)/i)    { $FilterIn{'host'}=&DecodeEncodedString("$1"); }            # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed
  5216.     if ($QueryString =~ /output=urldetail:([^&]+)/i)    { $FilterIn{'url'}=&DecodeEncodedString("$1"); }            # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed
  5217.     if ($QueryString =~ /output=refererpages:([^&]+)/i)    { $FilterIn{'refererpages'}=&DecodeEncodedString("$1"); }    # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed
  5218.  
  5219.     # If migrate
  5220.     if ($QueryString =~ /(^|-|&)migrate=([^&]+)/i)    {
  5221.         $MigrateStats=&DecodeEncodedString("$2"); 
  5222.         $MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/;
  5223.         $SiteConfig=$5?$5:'xxx'; $SiteConfig =~ s/^\.//;        # SiteConfig is used to find config file
  5224.     }
  5225. }
  5226. else {                                # Run from command line
  5227.     # Prepare QueryString
  5228.     for (0..@ARGV-1) {
  5229.         # If migrate
  5230.         if ($ARGV[$_] =~ /(^|-|&)migrate=([^&]+)/i) {
  5231.             $MigrateStats="$2";
  5232.             $MigrateStats =~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/;
  5233.             $SiteConfig=$5?$5:'xxx'; $SiteConfig =~ s/^\.//;    # SiteConfig is used to find config file
  5234.             next;
  5235.         }
  5236.         # TODO Check if ARGV is in @AllowedArg
  5237.         if ($QueryString) { $QueryString .= '&'; }
  5238.         my $NewLinkParams=$ARGV[$_]; $NewLinkParams =~ s/^-+//;
  5239.         $QueryString .= "$NewLinkParams";
  5240.     }
  5241.  
  5242.     $QueryString = CleanFromCSSA($QueryString);
  5243.     # Update with no report by default when run from command line
  5244.     $UpdateStats=1;
  5245.  
  5246.     if ($QueryString =~ /config=([^&]+)/i)                { $SiteConfig="$1"; }
  5247.     if ($QueryString =~ /logfile=([^&]+)/i)                { $LogFile="$1"; }
  5248.     if ($QueryString =~ /diricons=([^&]+)/i)            { $DirIcons="$1"; }
  5249.     if ($QueryString =~ /pluginmode=([^&]+)/i)            { $PluginMode="$1"; }
  5250.     if ($QueryString =~ /configdir=([^&]+)/i)            { $DirConfig="$1"; }
  5251.     # All filters
  5252.     if ($QueryString =~ /hostfilter=([^&]+)/i)            { $FilterIn{'host'}="$1"; }            # Filter on host list can also be defined with hostfilter=filter
  5253.     if ($QueryString =~ /hostfilterex=([^&]+)/i)        { $FilterEx{'host'}="$1"; }            #
  5254.     if ($QueryString =~ /urlfilter=([^&]+)/i)            { $FilterIn{'url'}="$1"; }            # Filter on URL list can also be defined with urlfilter=filter
  5255.     if ($QueryString =~ /urlfilterex=([^&]+)/i)            { $FilterEx{'url'}="$1"; }            #
  5256.     if ($QueryString =~ /refererpagesfilter=([^&]+)/i)    { $FilterIn{'refererpages'}="$1"; }    # Filter on referer list can also be defined with refererpagesfilter=filter
  5257.     if ($QueryString =~ /refererpagesfilterex=([^&]+)/i) { $FilterEx{'refererpages'}="$1"; } #
  5258.     # All output
  5259.     if ($QueryString =~ /output=allhosts:([^&]+)/i)        { $FilterIn{'host'}="$1"; }            # Filter on host list can be defined with output=allhosts:filter to reduce number of lines read and showed
  5260.     if ($QueryString =~ /output=lasthosts:([^&]+)/i)    { $FilterIn{'host'}="$1"; }            # Filter on host list can be defined with output=lasthosts:filter to reduce number of lines read and showed
  5261.     if ($QueryString =~ /output=urldetail:([^&]+)/i)    { $FilterIn{'url'}="$1"; }            # Filter on URL list can be defined with output=urldetail:filter to reduce number of lines read and showed
  5262.     if ($QueryString =~ /output=refererpages:([^&]+)/i)    { $FilterIn{'refererpages'}="$1"; }    # Filter on referer list can be defined with output=refererpages:filter to reduce number of lines read and showed
  5263.  
  5264.     # If show options
  5265.     if ($QueryString =~ /showsteps/i)                     { $ShowSteps=1; $QueryString=~s/showsteps[^&]*//i; }
  5266.     if ($QueryString =~ /showcorrupted/i)                 { $ShowCorrupted=1; $QueryString=~s/showcorrupted[^&]*//i; }
  5267.     if ($QueryString =~ /showdropped/i)                    { $ShowDropped=1; $QueryString=~s/showdropped[^&]*//i; }
  5268.     if ($QueryString =~ /showunknownorigin/i)            { $ShowUnknownOrigin=1; $QueryString=~s/showunknownorigin[^&]*//i; }
  5269. }
  5270. if ($QueryString =~ /(^|&)staticlinks/i)             { $StaticLinks=".$SiteConfig"; }
  5271. if ($QueryString =~ /(^|&)staticlinks=([^&]+)/i)     { $StaticLinks=".$2"; }        # When ran from awstatsbuildstaticpages.pl
  5272. if ($QueryString =~ /(^|&)staticlinksext=([^&]+)/i) { $StaticExt="$2"; }
  5273. if ($QueryString =~ /(^|&)framename=([^&]+)/i)        { $FrameName="$2"; }
  5274. if ($QueryString =~ /(^|&)debug=(\d+)/i)            { $Debug=$2; }
  5275. if ($QueryString =~ /(^|&)updatefor=(\d+)/i)        { $UpdateFor=$2; }
  5276. if ($QueryString =~ /(^|&)noloadplugin=([^&]+)/i)    { foreach (split(/,/,$2)) { $NoLoadPlugin{"$_"}=1; } }
  5277. if ($QueryString =~ /(^|&)loadplugin=([^&]+)/i)        { foreach (split(/,/,$2)) { $NoLoadPlugin{"$_"}=-1; } }
  5278. if ($QueryString =~ /(^|&)limitflush=(\d+)/i)        { $LIMITFLUSH=$2; }
  5279. # Get/Define output
  5280. if ($QueryString =~ /(^|&)output(=[^&]*|)(.*)&output(=[^&]*|)(&|$)/i) { error("Only 1 output option is allowed","","",1); }
  5281. if ($QueryString =~ /(^|&)output(=[^&]*|)(&|$)/i) {
  5282.     # At least one output expected. We define %HTMLOutput
  5283.     my $outputlist="$2";
  5284.     if ($outputlist) {
  5285.         $outputlist =~ s/^=//;
  5286.         foreach my $outputparam (split(/,/,$outputlist)) {
  5287.             $outputparam=~s/:(.*)$//;
  5288.             if ($outputparam) { $HTMLOutput{lc($outputparam)}="$1"||1; }
  5289.         }
  5290.     }
  5291.     # If on command line and no update
  5292.     if (! $ENV{'GATEWAY_INTERFACE'} && $QueryString !~ /update/i) { $UpdateStats=0; }
  5293.     # If no output defined, used default value
  5294.     if (! scalar keys %HTMLOutput) { $HTMLOutput{'main'}=1; }
  5295. }
  5296. if ($ENV{'GATEWAY_INTERFACE'} && ! scalar keys %HTMLOutput) { $HTMLOutput{'main'}=1; }
  5297.     
  5298. # Remove -output option with no = from QueryString
  5299. $QueryString=~s/(^|&)output(&|$)/$1/i; $QueryString=~s/&+$//;
  5300.  
  5301. # Check year and month parameters
  5302. if ($QueryString =~ /(^|&)month=(year)/i) { error("month=year is a deprecated option. Use month=all instead."); }
  5303. if ($QueryString =~ /(^|&)year=(\d\d\d\d)/i) { $YearRequired=sprintf("%04d",$2); }
  5304. else { $YearRequired="$nowyear"; }
  5305. if ($QueryString =~ /(^|&)month=(\d{1,2})/i) { $MonthRequired=sprintf("%02d",$2); }
  5306. elsif ($QueryString =~ /(^|&)month=(all)/i) { $MonthRequired='all'; }
  5307. else { $MonthRequired="$nowmonth"; }
  5308. if ($QueryString =~ /(^|&)day=(\d{1,2})/i) { $DayRequired=sprintf("%02d",$2); }    # day is a hidden option. Must not be used (Make results not understandable). Available for users that rename history files with day.
  5309. else { $DayRequired=''; }
  5310.  
  5311. # Check parameter validity
  5312. # TODO
  5313.  
  5314. # Print AWStats and Perl version 
  5315. if ($Debug) {
  5316.     debug(ucfirst($PROG)." - $VERSION - Perl $^X $]",1);
  5317.     debug("DIR=$DIR PROG=$PROG",2);
  5318.     debug("QUERY_STRING=$QueryString",2);
  5319.     debug("HTMLOutput=".join(',',keys %HTMLOutput),1);
  5320.     debug("YearRequired=$YearRequired, MonthRequired=$MonthRequired",2);
  5321.     debug("UpdateFor=$UpdateFor",2);
  5322.     debug("PluginMode=$PluginMode",2);
  5323.     debug("DirConfig=$DirConfig",2);
  5324. }
  5325.  
  5326. # Force SiteConfig if AWSTATS_FORCE_CONFIG is defined
  5327. if ($ENV{'AWSTATS_CONFIG'}) { $ENV{'AWSTATS_FORCE_CONFIG'}=$ENV{'AWSTATS_CONFIG'}; } # For backward compatibility
  5328. if ($ENV{'AWSTATS_FORCE_CONFIG'}) {
  5329.     if ($Debug) { debug("AWSTATS_FORCE_CONFIG parameter is defined to '".$ENV{'AWSTATS_FORCE_CONFIG'}."'. $PROG will use this as config value."); }
  5330.     $SiteConfig=$ENV{'AWSTATS_FORCE_CONFIG'};
  5331. }
  5332.  
  5333. if ((! $ENV{'GATEWAY_INTERFACE'}) && (! $SiteConfig)) {
  5334.     &Read_Ref_Data('browsers','domains','operating_systems','robots','search_engines','worms');
  5335.     print "----- $PROG $VERSION (c) Laurent Destailleur -----\n";
  5336.     print "$PROG is a free web server logfile analyzer to show you advanced web\n";
  5337.     print "statistics.\n";
  5338.     print "$PROG comes with ABSOLUTELY NO WARRANTY. It's a free software distributed\n";
  5339.     print "with a GNU General Public License (See LICENSE file for details).\n";
  5340.     print "\n";
  5341.     print "Syntax: $PROG.$Extension -config=virtualhostname [options]\n";
  5342.     print "\n";
  5343.     print "  This runs $PROG in command line to update statistics of a web site, from\n";
  5344.     print "  the log file defined in config file, and/or returns a HTML report.\n";
  5345.     print "  First, $PROG tries to read $PROG.virtualhostname.conf as the config file.\n";
  5346.     print "  If not found, $PROG tries to read $PROG.conf\n";
  5347.     print "  Note 1: Config files ($PROG.virtualhostname.conf or $PROG.conf) must be\n";
  5348.     print "   in /etc/awstats, /usr/local/etc/awstats, /etc or same directory than\n";
  5349.     print "   awstats.pl file.\n";
  5350.     print "  Note 2: If AWSTATS_FORCE_CONFIG environment variable is defined, AWStats will\n";
  5351.     print "   use it as the \"config\" value, whatever is the value on command line or URL.\n";
  5352.     print "   See AWStats documentation for all setup instrutions.\n";
  5353.     print "\n";
  5354.     print "Options to update statistics:\n";
  5355.     print "  -update        to update statistics (default)\n";
  5356.     print "  -showsteps     to add benchmark information every $NBOFLINESFORBENCHMARK lines processed\n";
  5357.     print "  -showcorrupted to add output for each corrupted lines found, with reason\n";
  5358.     print "  -showdropped   to add output for each dropped lines found, with reason\n";
  5359.     print "  -logfile=x     to change log to analyze whatever is 'LogFile' in config file\n";
  5360.     print "  -updatefor=n   to stop the update process after parsing n lines\n";
  5361.     print "  Be care to process log files in chronological order when updating statistics.\n";
  5362.     print "\n";
  5363.     print "Options to show statistics:\n";
  5364.     print "  -output      to output main HTML report (no update made except with -update)\n";
  5365.     print "  -output=x    to output other report pages where x is:\n";
  5366.     print "               alldomains       to build page of all domains/countries\n";
  5367.     print "               allhosts         to build page of all hosts\n";
  5368.     print "               lasthosts        to build page of last hits for hosts\n";
  5369.     print "               unknownip        to build page of all unresolved IP\n";
  5370.     print "               allemails        to build page of all email senders (maillog)\n";
  5371.     print "               lastemails       to build page of last email senders (maillog)\n";
  5372.     print "               allemailr        to build page of all email receivers (maillog)\n";
  5373.     print "               lastemailr       to build page of last email receivers (maillog)\n";
  5374.     print "               alllogins        to build page of all logins used\n";
  5375.     print "               lastlogins       to build page of last hits for logins\n";
  5376.     print "               allrobots        to build page of all robots/spider visits\n";
  5377.     print "               lastrobots       to build page of last hits for robots\n";
  5378.     print "               urldetail        to list most often viewed pages \n";
  5379.     print "               urldetail:filter to list most often viewed pages matching filter\n";
  5380.     print "               urlentry         to list entry pages\n";
  5381.     print "               urlentry:filter  to list entry pages matching filter\n";
  5382.     print "               urlexit          to list exit pages\n";
  5383.     print "               urlexit:filter   to list exit pages matching filter\n";
  5384.     print "               osdetail         to build page with os detailed versions\n";
  5385.     print "               browserdetail    to build page with browsers detailed versions\n";
  5386.     print "               unknownbrowser   to list 'User Agents' with unknown browser\n";
  5387.     print "               unknownos        to list 'User Agents' with unknown OS\n";
  5388.     print "               refererse        to build page of all refering search engines\n";
  5389.     print "               refererpages     to build page of all refering pages\n";
  5390.     #print "               referersites     to build page of all refering sites\n";
  5391.     print "               keyphrases       to list all keyphrases used on search engines\n";
  5392.     print "               keywords         to list all keywords used on search engines\n";
  5393.     print "               errors404        to list 'Referers' for 404 errors\n";
  5394.     print "  -staticlinks to have static links in HTML report page\n";
  5395.     print "  -staticlinksext=xxx to have static links with .xxx extension instead of .html\n";
  5396.     print "  -lang=LL     to output a HTML report in language LL (en,de,es,fr,it,nl,...)\n";
  5397.     print "  -month=MM    to output a HTML report for an old month MM\n";
  5398.     print "  -year=YYYY   to output a HTML report for an old year YYYY\n";
  5399.     print "  Those 'date' options doesn't allow you to process old log file. They only\n";
  5400.     print "  allow you to see a past report for a chosen month/year period instead of\n";
  5401.     print "  current month/year.\n";
  5402.     print "\n";
  5403.     print "Other options:\n";
  5404.     print "  -debug=X     to add debug informations lesser than level X (speed reduced)\n";
  5405.     print "\n";
  5406.     print "Now supports/detects:\n";
  5407.     print "  Web/Ftp/Mail log analyze (and load balanced log files)\n";
  5408.     print "  Reverse DNS lookup (IPv4 and IPv6) and GeoIP lookup\n";
  5409.     print "  Number of visits, number of unique visitors\n";
  5410.     print "  Visits duration and list of last visits\n";
  5411.     print "  Authenticated users\n";
  5412.     print "  Days of week and rush hours\n";
  5413.     print "  Hosts list and unresolved IP addresses list\n";
  5414.     print "  Most viewed, entry and exit pages\n";
  5415.     print "  Files type and Web compression (mod_gzip, mod_deflate stats)\n";
  5416.     print "  Screen size\n";
  5417.     print "  Number of times site is 'added to favorites bookmarks'\n";
  5418.     print "  Ratio of Browsers with support of: Java, Flash, RealG2 reader,\n";
  5419.     print "                        Quicktime reader, WMA reader, PDF reader\n";
  5420.     print "  Configurable personalized reports\n";
  5421.     print "  ".(scalar keys %DomainsHashIDLib)." domains/countries\n";
  5422.     print "  ".(scalar keys %RobotsHashIDLib)." robots\n";
  5423.     print "  ".(scalar keys %WormsHashLib)." worm's families\n";
  5424.     print "  ".(scalar keys %OSHashLib)." operating systems\n";
  5425.     print "  ".(scalar keys %BrowsersHashIDLib)." browsers\n";
  5426.     print "  ".(scalar keys %SearchEnginesHashLib)." search engines (and keyphrases/keywords used from them)\n";
  5427.     print "  All HTTP errors with last referrer\n";
  5428.     print "  Report by day/month/year\n";
  5429.     print "  Dynamic or static HTML reports, static PDF reports\n";
  5430.     print "  And a lot of other advanced features and options...\n";
  5431.     print "New versions and FAQ at http://awstats.sourceforge.net\n";
  5432.     exit 2;
  5433. }
  5434. $SiteConfig||=$ENV{'SERVER_NAME'};
  5435. #$ENV{'SERVER_NAME'}||=$SiteConfig;    # For thoose who use __SERVER_NAME__ in conf file and use CLI.
  5436. $ENV{'AWSTATS_CURRENT_CONFIG'}=$SiteConfig;
  5437.  
  5438. # Read config file (SiteConfig must be defined)
  5439. &Read_Config($DirConfig);
  5440.  
  5441. # Check language
  5442. if ($QueryString =~ /(^|&)lang=([^&]+)/i)    { $Lang="$2"; }
  5443. if (! $Lang || $Lang eq 'auto') {    # If lang not defined or forced to auto
  5444.     my $langlist=$ENV{'HTTP_ACCEPT_LANGUAGE'}||''; $langlist =~ s/;[^,]*//g;
  5445.     if ($Debug) { debug("Search an available language among HTTP_ACCEPT_LANGUAGE=$langlist",1); }
  5446.     foreach my $code (split(/,/,$langlist)) {    # Search for a valid lang in priority
  5447.         if ($LangBrowserToLangAwstats{$code}) { $Lang=$LangBrowserToLangAwstats{$code}; if ($Debug) { debug(" Will try to use Lang=$Lang",1); } last; }
  5448.         $code =~ s/-.*$//;
  5449.         if ($LangBrowserToLangAwstats{$code}) { $Lang=$LangBrowserToLangAwstats{$code}; if ($Debug) { debug(" Will try to use Lang=$Lang",1); } last; }
  5450.     }
  5451. }
  5452. if (! $Lang || $Lang eq 'auto') {
  5453.     if ($Debug) { debug(" No language defined or available. Will use Lang=en",1); }
  5454.     $Lang='en';
  5455. }
  5456.  
  5457. # Check and correct bad parameters
  5458. &Check_Config();
  5459. # Now SiteDomain is defined
  5460.  
  5461. # Define frame name and correct variable for frames
  5462. if (! $FrameName) {
  5463.     if ($ENV{'GATEWAY_INTERFACE'} && $UseFramesWhenCGI && $HTMLOutput{'main'} && ! $PluginMode) { $FrameName='index'; }
  5464.     else { $FrameName='main'; }
  5465. }
  5466.  
  5467. # Load Message files, Reference data files and Plugins
  5468. if ($Debug) { debug("FrameName=$FrameName",1); }
  5469. if ($FrameName ne 'index') {
  5470.     &Read_Language_Data($Lang);
  5471.     if ($FrameName ne 'mainleft') {
  5472.         my %datatoload=();
  5473.         if ($UpdateStats) {                # If update
  5474.             if ($LevelForFileTypesDetection<2)    { $datatoload{'mime'}=1; }        # Only if need to filter on known extensions
  5475.             if ($LevelForRobotsDetection)         { $datatoload{'robots'}=1; }    # ua
  5476.             if ($LevelForWormsDetection)         { $datatoload{'worms'}=1; }        # url
  5477.             if ($LevelForBrowsersDetection)        { $datatoload{'browsers'}=1; }    # ua
  5478.             if ($LevelForOSDetection)            { $datatoload{'operating_systems'}=1; }    # ua
  5479.             if ($LevelForRefererAnalyze)        { $datatoload{'search_engines'}=1; }    # referer
  5480.             # if (...) { $datatoload{'referer_spam'}=1; }
  5481.         }
  5482.         if (scalar keys %HTMLOutput) {    # If output
  5483.             if ($ShowDomainsStats)                 { $datatoload{'domains'}=1; }
  5484.             if ($ShowFileTypesStats)             { $datatoload{'mime'}=1; }
  5485.             if ($ShowRobotsStats)                 { $datatoload{'robots'}=1; }
  5486.             if ($ShowWormsStats)                 { $datatoload{'worms'}=1; }
  5487.             if ($ShowBrowsersStats)             { $datatoload{'browsers'}=1; }
  5488.             if ($ShowOSStats)                     { $datatoload{'operating_systems'}=1; }
  5489.             if ($ShowOriginStats)                 { $datatoload{'search_engines'}=1; }
  5490.             if ($ShowHTTPErrorsStats)             { $datatoload{'status_http'}=1; }
  5491.             if ($ShowSMTPErrorsStats)             { $datatoload{'status_smtp'}=1; }
  5492.         }
  5493.         &Read_Ref_Data(keys %datatoload);
  5494.         &Read_Plugins();
  5495.     }
  5496. }
  5497. # Here charset is defined, so we can send the http header (Need BuildReportFormat,PageCode)
  5498. if (! $HeaderHTTPSent && $ENV{'GATEWAY_INTERFACE'}) { http_head(); }    # Run from a browser as CGI
  5499.  
  5500. # Init other parameters
  5501. $NBOFLINESFORBENCHMARK--;
  5502. if ($ENV{'GATEWAY_INTERFACE'}) { $DirCgi=''; }
  5503. if ($DirCgi && !($DirCgi =~ /\/$/) && !($DirCgi =~ /\\$/)) { $DirCgi .= '/'; }
  5504. if (! $DirData || $DirData =~ /^\./) {
  5505.      if (! $DirData || $DirData eq '.') { $DirData="$DIR"; }      # If not defined or chosen to '.' value then DirData is current dir
  5506.      elsif ($DIR && $DIR ne '.') { $DirData="$DIR/$DirData"; }
  5507. }
  5508. $DirData||='.';        # If current dir not defined then we put it to '.'
  5509. $DirData =~ s/[\\\/]+$//;
  5510.  
  5511. if ($FirstDayOfWeek == 1) { @DOWIndex = (1,2,3,4,5,6,0); }
  5512. else { @DOWIndex = (0,1,2,3,4,5,6); }
  5513.  
  5514. # Should we link to ourselves or to a wrapper script
  5515. $AWScript=($WrapperScript?"$WrapperScript":"$DirCgi$PROG.$Extension");
  5516.  
  5517. # Print html header (Need HTMLOutput,Expires,Lang,StyleSheet,HTMLHeadSectionExpires defined by Read_Config, PageCode defined by Read_Language_Data)
  5518. if (! $HeaderHTMLSent) { &html_head; }
  5519.  
  5520. # AWStats output is replaced by a plugin output
  5521. if ($PluginMode) {
  5522.     my $function="BuildFullHTMLOutput_$PluginMode()";
  5523.     eval("$function");
  5524.     if ($? || $@) { error("$@"); }
  5525.     &html_end(0);
  5526.     exit 0;    
  5527. }
  5528.  
  5529. # Security check
  5530. if ($AllowAccessFromWebToAuthenticatedUsersOnly && $ENV{'GATEWAY_INTERFACE'}) {
  5531.     if ($Debug) { debug("REMOTE_USER=".$ENV{"REMOTE_USER"}); }
  5532.     if (! $ENV{"REMOTE_USER"}) {
  5533.         error("Access to statistics is only allowed from an authenticated session to authenticated users.");
  5534.     }
  5535.     if (@AllowAccessFromWebToFollowingAuthenticatedUsers) {
  5536.         my $userisinlist=0;
  5537.         my $currentuser=qr/^$ENV{"REMOTE_USER"}$/i;
  5538.         $currentuser =~ s/\s/%20/g;    # Allow authenticated user with space in name to be compared to allowed user list
  5539.         foreach (@AllowAccessFromWebToFollowingAuthenticatedUsers) {
  5540.             if (/$currentuser/o) { $userisinlist=1; last; }
  5541.         }
  5542.         if (! $userisinlist) {
  5543.             error("User '".$ENV{"REMOTE_USER"}."' is not allowed to access statistics of this domain/config.");
  5544.         }
  5545.     }
  5546. }
  5547. if ($AllowAccessFromWebToFollowingIPAddresses && $ENV{'GATEWAY_INTERFACE'}) {
  5548.     my $useripaddress=&Convert_IP_To_Decimal($ENV{"REMOTE_ADDR"});
  5549.     my @allowaccessfromipaddresses = split (/[\s,]+/, $AllowAccessFromWebToFollowingIPAddresses);
  5550.     my $allowaccess = 0;
  5551.     foreach my $ipaddressrange (@allowaccessfromipaddresses) {
  5552.         if ($ipaddressrange !~ /^(\d+\.\d+\.\d+\.\d+)(?:-(\d+\.\d+\.\d+\.\d+))*$/) {
  5553.             error("AllowAccessFromWebToFollowingIPAddresses is defined to '$AllowAccessFromWebToFollowingIPAddresses' but does not match the correct syntax: IPAddressMin[-IPAddressMax]");
  5554.         }
  5555.         my $ipmin=&Convert_IP_To_Decimal($1);
  5556.         my $ipmax=$2?&Convert_IP_To_Decimal($2):$ipmin;
  5557.         # Is it an authorized ip ?
  5558.         if (($useripaddress >= $ipmin) && ($useripaddress <= $ipmax)) {
  5559.             $allowaccess = 1;
  5560.             last;
  5561.         }
  5562.     }
  5563.     if (! $allowaccess) {
  5564.         error("Access to statistics is not allowed from your IP Address ".$ENV{"REMOTE_ADDR"});
  5565.     }
  5566. }
  5567. if (($UpdateStats || $MigrateStats) && (! $AllowToUpdateStatsFromBrowser) && $ENV{'GATEWAY_INTERFACE'}) {
  5568.     error("".($UpdateStats?"Update":"Migrate")." of statistics has not been allowed from a browser (AllowToUpdateStatsFromBrowser should be set to 1).");
  5569. }
  5570. if (scalar keys %HTMLOutput && $MonthRequired eq 'all') {
  5571.     if (! $AllowFullYearView) { error("Full year view has not been allowed (AllowFullYearView is set to 0)."); }
  5572.     if ($AllowFullYearView < 3 && $ENV{'GATEWAY_INTERFACE'}) { error("Full year view has not been allowed from a browser (AllowFullYearView should be set to 3)."); }
  5573. }
  5574.  
  5575.  
  5576. #------------------------------------------
  5577. # MIGRATE PROCESS (Must be after reading config cause we need MaxNbOf... and Min...)
  5578. #------------------------------------------
  5579. if ($MigrateStats) {
  5580.     if ($Debug) { debug("MigrateStats is $MigrateStats",2); }
  5581.     if ($MigrateStats !~ /^(.*)$PROG(\d{0,2})(\d\d)(\d\d\d\d)(.*)\.txt$/) {
  5582.         error("AWStats history file name must match following syntax: ${PROG}MMYYYY[.config].txt","","",1);
  5583.     }
  5584.     $DirData="$1";
  5585.     $DayRequired="$2";
  5586.     $MonthRequired="$3";
  5587.     $YearRequired="$4";
  5588.     $FileSuffix="$5";
  5589.     # Correct DirData
  5590.     if (! $DirData || $DirData =~ /^\./) {
  5591.          if (! $DirData || $DirData eq '.') { $DirData="$DIR"; }      # If not defined or chosen to '.' value then DirData is current dir
  5592.          elsif ($DIR && $DIR ne '.') { $DirData="$DIR/$DirData"; }
  5593.     }
  5594.     $DirData||='.';        # If current dir not defined then we put it to '.'
  5595.     $DirData =~ s/[\\\/]+$//;
  5596.     print "Start migration for file '$MigrateStats'."; print $ENV{'GATEWAY_INTERFACE'}?"<br />\n":"\n";
  5597.     if ($EnableLockForUpdate) {    &Lock_Update(1); }
  5598.     my $newhistory=&Read_History_With_TmpUpdate($YearRequired,$MonthRequired,1,0,'all');
  5599.     if (rename("$newhistory","$MigrateStats")==0) {
  5600.         unlink "$newhistory";
  5601.         error("Failed to rename \"$newhistory\" into \"$MigrateStats\".\nWrite permissions on \"$MigrateStats\" might be wrong".($ENV{'GATEWAY_INTERFACE'}?" for a 'migration from web'":"")." or file might be opened.");
  5602.     }
  5603.     if ($EnableLockForUpdate) {    &Lock_Update(0); }
  5604.     print "Migration for file '$MigrateStats' successful."; print $ENV{'GATEWAY_INTERFACE'}?"<br />\n":"\n";
  5605.     &html_end(1);
  5606.     exit 0;
  5607. }
  5608.  
  5609. # Output main frame page and exit. This must be after the security check.
  5610. if ($FrameName eq 'index') {
  5611.     # Define the NewLinkParams for main chart
  5612.     my $NewLinkParams=${QueryString};
  5613.     $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  5614.     $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  5615.     if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  5616.     # Exit if main frame
  5617.     print "<frameset cols=\"$FRAMEWIDTH,*\" border=\"0\" framespacing=\"2\" frameborder=\"0\">\n";
  5618.     print "<frame name=\"mainleft\" src=\"".XMLEncode("$AWScript?${NewLinkParams}framename=mainleft")."\" noresize=\"0\" frameborder=\"0\" />\n";
  5619.     print "<frame name=\"mainright\" src=\"".XMLEncode("$AWScript?${NewLinkParams}framename=mainright")."\" noresize=\"0\" scrolling=\"YES\" frameborder=\"0\" />\n";
  5620.     print "<noframes><body>";
  5621.     print "Your browser does not support frames.<br />\n";
  5622.     print "You must set AWStats UseFramesWhenCGI parameter to 0\n";
  5623.     print "to see your reports.<br />\n";
  5624.     print "</body></noframes>\n";
  5625.     print "</frameset>\n";
  5626.     &html_end(0);
  5627.     exit 0;
  5628. }
  5629.  
  5630. %MonthNumLib = ("01","$Message[60]","02","$Message[61]","03","$Message[62]","04","$Message[63]","05","$Message[64]","06","$Message[65]","07","$Message[66]","08","$Message[67]","09","$Message[68]","10","$Message[69]","11","$Message[70]","12","$Message[71]");
  5631.  
  5632. # Build ListOfYears list with all existing years
  5633. if ($Debug) { debug("Scan for last history files into DirData='$DirData'"); }
  5634. $lastyearbeforeupdate=0;
  5635. opendir(DIR,"$DirData");
  5636. foreach (grep /^$PROG(\d\d)(\d\d\d\d)$FileSuffix\.txt(|\.gz)$/, sort readdir DIR) {
  5637.     /^$PROG(\d\d)(\d\d\d\d)$FileSuffix\.txt(|\.gz)$/;
  5638.     if (! $ListOfYears{"$2"} || "$1" gt $ListOfYears{"$2"}) {
  5639.         $ListOfYears{"$2"}="$1";    # ListOfYears contains max month found
  5640.         if ("$2" gt $lastyearbeforeupdate) { $lastyearbeforeupdate="$2"; }
  5641.     }
  5642. }
  5643. close DIR;
  5644.  
  5645. # Get value for LastLine
  5646. if ($lastyearbeforeupdate) {
  5647.     # Read 'general' section of last history file for LastLine
  5648.     &Read_History_With_TmpUpdate($lastyearbeforeupdate,$ListOfYears{$lastyearbeforeupdate},0,0,"general");
  5649. }
  5650. if ($Debug) {
  5651.     debug("Last year=$lastyearbeforeupdate - Last month=$ListOfYears{$lastyearbeforeupdate}");
  5652.     debug("LastLine=$LastLine");
  5653.     debug("LastLineNumber=$LastLineNumber");
  5654.     debug("LastLineOffset=$LastLineOffset");
  5655.     debug("LastLineChecksum=$LastLineChecksum");
  5656. }
  5657.  
  5658. # Init vars
  5659. &Init_HashArray();
  5660.  
  5661.  
  5662. #------------------------------------------
  5663. # UPDATE PROCESS
  5664. #------------------------------------------
  5665. my $lastlinenb=0; my $lastlineoffset=0; my $lastlineoffsetnext=0;
  5666.  
  5667. if ($Debug) { debug("UpdateStats is $UpdateStats",2); }
  5668. if ($UpdateStats && $FrameName ne 'index' && $FrameName ne 'mainleft') {    # Update only on index page or when not framed to avoid update twice
  5669.  
  5670.     my %MonthNum = ("Jan","01","jan","01","Feb","02","feb","02","Mar","03","mar","03","Apr","04","apr","04","May","05","may","05","Jun","06","jun","06","Jul","07","jul","07","Aug","08","aug","08","Sep","09","sep","09","Oct","10","oct","10","Nov","11","nov","11","Dec","12","dec","12");    # MonthNum must be in english because used to translate log date in apache log files
  5671.  
  5672.     if (! scalar keys %HTMLOutput) {
  5673.         print "Update for config \"$FileConfig\"\n";
  5674.         print "With data in log file \"$LogFile\"...\n";
  5675.     }
  5676.  
  5677.     my $lastprocessedyear=$lastyearbeforeupdate;
  5678.     my $lastprocessedmonth=$ListOfYears{$lastyearbeforeupdate}||0;
  5679.     my $lastprocessedyearmonth=sprintf("%04i%02i",$lastprocessedyear,$lastprocessedmonth);
  5680.  
  5681.     my @list;
  5682.     # Init RobotsSearchIDOrder required for update process
  5683.     @list=();
  5684.     if ($LevelForRobotsDetection >= 1) {
  5685.         foreach (1..$LevelForRobotsDetection) { push @list,"list$_"; }
  5686.         push @list,"listgen";        # Always added
  5687.     }
  5688.     foreach my $key (@list) {
  5689.         push @RobotsSearchIDOrder,@{"RobotsSearchIDOrder_$key"};
  5690.         if ($Debug) { debug("Add ".@{"RobotsSearchIDOrder_$key"}." elements from RobotsSearchIDOrder_$key into RobotsSearchIDOrder",2); }
  5691.     }
  5692.     if ($Debug) { debug("RobotsSearchIDOrder has now ".@RobotsSearchIDOrder." elements",1); }
  5693.     # Init SearchEnginesIDOrder required for update process
  5694.     @list=();
  5695.     if ($LevelForSearchEnginesDetection >= 1) {
  5696.         foreach (1..$LevelForSearchEnginesDetection) { push @list,"list$_"; }
  5697.         push @list,"listgen";        # Always added
  5698.     }
  5699.     foreach my $key (@list) {
  5700.         push @SearchEnginesSearchIDOrder,@{"SearchEnginesSearchIDOrder_$key"};
  5701.         if ($Debug) { debug("Add ".@{"SearchEnginesSearchIDOrder_$key"}." elements from SearchEnginesSearchIDOrder_$key into SearchEnginesSearchIDOrder",2); }
  5702.     }
  5703.     if ($Debug) { debug("SearchEnginesSearchIDOrder has now ".@SearchEnginesSearchIDOrder." elements",1); }
  5704.  
  5705.     # Complete HostAliases array
  5706.     my $sitetoanalyze=quotemeta(lc($SiteDomain));
  5707.     if (! @HostAliases) {
  5708.         warning("Warning: HostAliases parameter is not defined, $PROG choose \"$SiteDomain localhost 127.0.0.1\".");
  5709.         push @HostAliases,qr/^$sitetoanalyze$/i; push @HostAliases,qr/^localhost$/i; push @HostAliases,qr/^127\.0\.0\.1$/i;
  5710.     }
  5711.     else { unshift @HostAliases,qr/^$sitetoanalyze$/i; }    # Add SiteDomain as first value
  5712.  
  5713.     # Optimize arrays
  5714.     @HostAliases=&OptimizeArray(\@HostAliases,1); if ($Debug) { debug("HostAliases precompiled regex list is now @HostAliases",1); }
  5715.     @SkipDNSLookupFor=&OptimizeArray(\@SkipDNSLookupFor,1); if ($Debug) { debug("SkipDNSLookupFor precompiled regex list is now @SkipDNSLookupFor",1); }
  5716.     @SkipHosts=&OptimizeArray(\@SkipHosts,1); if ($Debug) { debug("SkipHosts precompiled regex list is now @SkipHosts",1); }
  5717.     @SkipUserAgents=&OptimizeArray(\@SkipUserAgents,1); if ($Debug) { debug("SkipUserAgents precompiled regex list is now @SkipUserAgents",1); }
  5718.     @SkipFiles=&OptimizeArray(\@SkipFiles,$URLNotCaseSensitive); if ($Debug) { debug("SkipFiles precompiled regex list is now @SkipFiles",1); }
  5719.     @OnlyHosts=&OptimizeArray(\@OnlyHosts,1); if ($Debug) { debug("OnlyHosts precompiled regex list is now @OnlyHosts",1); }
  5720.     @OnlyUserAgents=&OptimizeArray(\@OnlyUserAgents,1); if ($Debug) { debug("OnlyUserAgents precompiled regex list is now @OnlyUserAgents",1); }
  5721.     @OnlyFiles=&OptimizeArray(\@OnlyFiles,$URLNotCaseSensitive); if ($Debug) { debug("OnlyFiles precompiled regex list is now @OnlyFiles",1); }
  5722.     # Precompile the regex search strings with qr
  5723.     @RobotsSearchIDOrder=map{qr/$_/i} @RobotsSearchIDOrder;
  5724.     @WormsSearchIDOrder=map{qr/$_/i} @WormsSearchIDOrder;
  5725.     @BrowsersSearchIDOrder=map{qr/$_/i} @BrowsersSearchIDOrder;
  5726.     @OSSearchIDOrder=map{qr/$_/i} @OSSearchIDOrder;
  5727.     @SearchEnginesSearchIDOrder=map{qr/$_/i} @SearchEnginesSearchIDOrder;
  5728.     my $miscquoted=quotemeta("$MiscTrackerUrl");
  5729.     my $defquoted=quotemeta("/$DefaultFile[0]");
  5730.     my $sitewithoutwww=lc($SiteDomain); $sitewithoutwww =~ s/www\.//; $sitewithoutwww=quotemeta($sitewithoutwww);
  5731.     # Define precompiled regex
  5732.     my $regmisc=qr/^$miscquoted/;
  5733.     my $regfavico=qr/\/favicon\.ico$/i;
  5734.     my $regrobot=qr/^\/robots\.txt$/i;
  5735.     my $regtruncanchor=qr/#(\w*)$/;
  5736.     my $regtruncurl=qr/([$URLQuerySeparators])(.*)$/;
  5737.     my $regext=qr/\.(\w{1,6})$/;
  5738.     my $regdefault;
  5739.     if ($URLNotCaseSensitive) { $regdefault=qr/$defquoted$/i; }
  5740.     else { $regdefault=qr/$defquoted$/; }
  5741.     my $regipv4=qr/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
  5742.     my $regipv6=qr/^[0-9A-F]*:/i;
  5743.     my $regvermsie=qr/msie([+_ ]|)([\d\.]*)/i;
  5744.     my $regvernetscape=qr/netscape.?\/([\d\.]*)/i;
  5745.     my $regvermozilla=qr/mozilla(\/|)([\d\.]*)/i;
  5746.     my $regnotie=qr/webtv|omniweb|opera/i;
  5747.     my $regnotnetscape=qr/gecko|compatible|opera|galeon|safari/i;
  5748.     my $regreferer=qr/^(\w+):\/\/([^\/:]+)(:\d+|)/;
  5749.     my $regreferernoquery=qr/^([^$URLQuerySeparators]+)/;
  5750.     my $reglocal=qr/^(www\.|)$sitewithoutwww/i;
  5751.  
  5752.     # Define value of $PerlParsingFormat and @fieldlib
  5753.     &DefinePerlParsingFormat();
  5754.  
  5755.     # Load DNS Cache Files
  5756.     #------------------------------------------
  5757.     if ($DNSLookup) {
  5758.         &Read_DNS_Cache(\%MyDNSTable,"$DNSStaticCacheFile","",1);                        # Load with save into a second plugin file if plugin enabled and second file not up to date. No use of FileSuffix
  5759.         if ($DNSLookup == 1) {        # System DNS lookup required
  5760.             #if (! eval("use Socket;")) { error("Failed to load perl module Socket."); }
  5761.             #use Socket;
  5762.             &Read_DNS_Cache(\%TmpDNSLookup,"$DNSLastUpdateCacheFile","$FileSuffix",0);    # Load with no save into a second plugin file. Use FileSuffix
  5763.         }
  5764.     }
  5765.  
  5766.     # Processing log
  5767.     #------------------------------------------
  5768.  
  5769.     if ($EnableLockForUpdate) {
  5770.         # Trap signals to remove lock
  5771.         $SIG{INT} = \&SigHandler;    # 2
  5772.         #$SIG{KILL} = \&SigHandler;    # 9
  5773.         #$SIG{TERM} = \&SigHandler;    # 15
  5774.         # Set AWStats update lock
  5775.         &Lock_Update(1);
  5776.     }
  5777.  
  5778.     if ($Debug) { debug("Start Update process (lastprocessedmonth=$lastprocessedmonth, lastprocessedyear=$lastprocessedyear)"); }
  5779.  
  5780.     # Open log file
  5781.     if ($Debug) { debug("Open log file \"$LogFile\""); }
  5782.     open(LOG,"$LogFile") || error("Couldn't open server log file \"$LogFile\" : $!");
  5783.     binmode LOG;    # Avoid premature EOF due to log files corrupted with \cZ or bin chars
  5784.  
  5785.     # Define local variables for loop scan
  5786.     my @field=();
  5787.     my $counterforflushtest=0;
  5788.     my $qualifdrop='';
  5789.     my $countedtraffic=0;
  5790.     # Reset chrono for benchmark (first call to GetDelaySinceStart)
  5791.     &GetDelaySinceStart(1);
  5792.     if (! scalar keys %HTMLOutput) { print "Phase 1 : First bypass old records, searching new record...\n"; }
  5793.  
  5794.     # Can we try a direct seek access in log ?
  5795.     my $line;
  5796.     if ($LastLine && $LastLineNumber && $LastLineOffset && $LastLineChecksum) {
  5797.         # Try a direct seek access to save time
  5798.         if ($Debug) { debug("Try a direct access to LastLine=$LastLine, LastLineNumber=$LastLineNumber, LastLineOffset=$LastLineOffset, LastLineChecksum=$LastLineChecksum"); }
  5799.         seek(LOG,$LastLineOffset,0);
  5800.         if ($line=<LOG>) {
  5801.             chomp $line; $line =~ s/\r$//;
  5802.             @field=map(/$PerlParsingFormat/,$line);
  5803.             if ($Debug) {
  5804.                 my $string='';
  5805.                 foreach (0..@field-1) {    $string.="$fieldlib[$_]=$field[$_] "; }
  5806.                 if ($Debug) { debug(" Read line after direct access: $string",1); }
  5807.             }
  5808.             my $checksum=&CheckSum($line);
  5809.             if ($Debug) { debug(" LastLineChecksum=$LastLineChecksum, Read line checksum=$checksum",1); }
  5810.             if ($checksum == $LastLineChecksum ) {
  5811.                 if (! scalar keys %HTMLOutput) { print "Direct access after last parsed record (after line $LastLineNumber)\n"; }
  5812.                 $lastlinenb=$LastLineNumber;
  5813.                 $lastlineoffset=$LastLineOffset;
  5814.                 $lastlineoffsetnext=tell LOG;
  5815.                 #seek(LOG,$LastLineOffset,0);$lastlineoffsetnext=$LastLineOffset;    # Direct access succesful, we keep it.
  5816.             }
  5817.             else {
  5818.                 if (! scalar keys %HTMLOutput) { print "Direct access to last remembered record has fallen on another record.\nSo searching new records from beginning of log file...\n"; }
  5819.                 $lastlinenb=0;
  5820.                 $lastlineoffset=0;
  5821.                 $lastlineoffsetnext=0;
  5822.                 seek(LOG,0,0);
  5823.             }
  5824.         }
  5825.         else {
  5826.             if (! scalar keys %HTMLOutput) { print "Direct access to last remembered record is out of file.\nSo searching it from beginning of log file...\n"; }
  5827.             $lastlinenb=0;
  5828.             $lastlineoffset=0;
  5829.             $lastlineoffsetnext=0;
  5830.             seek(LOG,0,0);
  5831.         }
  5832.     }
  5833.     else {
  5834.         # No try of direct seek access
  5835.         if (! scalar keys %HTMLOutput) { print "Searching new records from beginning of log file...\n"; }
  5836.         $lastlinenb=0;
  5837.         $lastlineoffset=0;
  5838.         $lastlineoffsetnext=0;
  5839.     }
  5840.  
  5841.     while ($line=<LOG>) {
  5842.         chomp $line; $line =~ s/\r$//;
  5843.         if ($UpdateFor && $NbOfLinesParsed >= $UpdateFor) { last; }
  5844.         $NbOfLinesParsed++;
  5845.  
  5846.          $lastlineoffset=$lastlineoffsetnext; $lastlineoffsetnext=tell LOG;
  5847.  
  5848.         if ($ShowSteps) {
  5849.             if ((++$NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK) == 0) {
  5850.                 my $delay=&GetDelaySinceStart(0);
  5851.                 print "$NbOfLinesParsed lines processed (".($delay>0?$delay:1000)." ms, ".int(1000*$NbOfLinesShowsteps/($delay>0?$delay:1000))." lines/second)\n";
  5852.             }
  5853.         }
  5854.  
  5855.         # Parse line record to get all required fields
  5856.         if (! (@field=map(/$PerlParsingFormat/,$line))) {
  5857.             $NbOfLinesCorrupted++;
  5858.             if ($ShowCorrupted) {
  5859.                 if ($line =~ /^#/ || $line =~ /^!/) { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (comment line): $line\n"; }
  5860.                 elsif ($line =~ /^\s*$/) { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (blank line)\n"; }
  5861.                 else { print "Corrupted record line ".($lastlinenb+$NbOfLinesParsed)." (record format does not match LogFormat parameter): $line\n"; }
  5862.             }
  5863.             if ($NbOfLinesParsed >= $NbOfLinesForCorruptedLog && $NbOfLinesParsed == $NbOfLinesCorrupted) { error("Format error",$line,$LogFile); }    # Exit with format error
  5864.             if ($line =~ /^__end_of_file__/i) { last; }    # For test purpose only
  5865.             next;
  5866.         }
  5867.  
  5868.         if ($Debug) {
  5869.             my $string='';
  5870.             foreach (0..@field-1) {    $string.="$fieldlib[$_]=$field[$_] "; }
  5871.             if ($Debug) { debug(" Correct format line ".($lastlinenb+$NbOfLinesParsed).": $string",4); }
  5872.         }
  5873.  
  5874.         # Drop wrong virtual host name
  5875.         #----------------------------------------------------------------------
  5876.         if ($pos_vh>=0 && $field[$pos_vh] !~ /^$SiteDomain$/i) {
  5877.             my $skip=1;
  5878.             foreach (@HostAliases) {
  5879.                 if ($field[$pos_vh] =~ /$_/) { $skip=0; last; }
  5880.             }
  5881.             if ($skip) {
  5882.                 $NbOfLinesDropped++;
  5883.                 if ($ShowDropped) { print "Dropped record (virtual hostname '$field[$pos_vh]' does not match SiteDomain='$SiteDomain' nor HostAliases parameters): $line\n"; }
  5884.                 next;
  5885.             }
  5886.         }
  5887.  
  5888.         # Drop wrong method/protocol
  5889.         #---------------------------
  5890.         if ($LogType ne 'M') { $field[$pos_url] =~ s/\s/%20/g; }
  5891.         if ($LogType eq 'W' && ($field[$pos_method] eq 'GET' || $field[$pos_method] eq 'POST' || $field[$pos_method] eq 'HEAD' || $field[$pos_method] =~ /OK/i || $field[$pos_method] =~ /ERR\!/i)) {
  5892.             # HTTP request.    Keep only GET, POST, HEAD, *OK* and ERR! for Webstar. Do not keep OPTIONS, TRACE
  5893.         }
  5894.         elsif (($LogType eq 'W' || $LogType eq 'S') && ($field[$pos_method] eq 'GET' || $field[$pos_method] eq 'mms' || $field[$pos_method] eq 'rtsp' || $field[$pos_method] eq 'http' || $field[$pos_method] eq 'RTP')) {
  5895.             # Streaming request (windows media server, realmedia or darwin streaming server)
  5896.         }
  5897.         elsif ($LogType eq 'M' && $field[$pos_method] eq 'SMTP') {
  5898.             # Mail request ('SMTP' for mail log with maillogconvert.pl preprocessor)
  5899.         }
  5900.         elsif ($LogType eq 'F' && ($field[$pos_method] eq 'RETR' || $field[$pos_method] eq 'o' || $field[$pos_method] =~ /get/i)) {
  5901.             # FTP GET request
  5902.         }
  5903.         elsif ($LogType eq 'F' && ($field[$pos_method] eq 'STOR' || $field[$pos_method] eq 'i' || $field[$pos_method] =~ /sent/i)) {
  5904.             # FTP SENT request
  5905.         }
  5906.         else {
  5907.             $NbOfLinesDropped++;
  5908.             if ($ShowDropped) { print "Dropped record (method/protocol '$field[$pos_method]' not qualified when LogType=$LogType): $line\n"; }
  5909.             next;
  5910.         }
  5911.  
  5912.         # Split DD/Month/YYYY:HH:MM:SS or YYYY-MM-DD HH:MM:SS or MM/DD/YY\tHH:MM:SS
  5913.         $field[$pos_date] =~ tr/,-\/ \t/:::::/;            # " \t" is used instead of "\s" not known with tr
  5914.         my @dateparts=split(/:/,$field[$pos_date]);        # tr and split faster than @dateparts=split(/[\/\-:\s]/,$field[$pos_date])
  5915.         if (! $dateparts[1]) {    # Unix timestamp
  5916.             ($dateparts[5],$dateparts[4],$dateparts[3],$dateparts[0],$dateparts[1],$dateparts[2]) = localtime(int($field[$pos_date]));
  5917.             $dateparts[1]++;$dateparts[2]+=1900;
  5918.         }
  5919.         elsif ($dateparts[0] =~ /^....$/) { my $tmp=$dateparts[0]; $dateparts[0]=$dateparts[2]; $dateparts[2]=$tmp; }
  5920.         elsif ($field[$pos_date] =~ /^..:..:..:/) { $dateparts[2]+=2000; my $tmp=$dateparts[0]; $dateparts[0]=$dateparts[1]; $dateparts[1]=$tmp; }
  5921.         if ($MonthNum{$dateparts[1]}) { $dateparts[1]=$MonthNum{$dateparts[1]}; }    # Change lib month in num month if necessary
  5922.         
  5923.         # Now @dateparts is (DD,MM,YYYY,HH,MM,SS) and we're going to create $timerecord=YYYYMMDDHHMMSS
  5924.         # Plugin call : Convert a @datepart into another @datepart
  5925.         if ($PluginsLoaded{'ChangeTime'}{'timezone'})  { @dateparts=ChangeTime_timezone(\@dateparts); }
  5926.         my $yearrecord=int($dateparts[2]);
  5927.         my $monthrecord=int($dateparts[1]);
  5928.         my $hourrecord=int($dateparts[3]);
  5929.         my $yearmonthdayrecord=sprintf("$dateparts[2]%02i%02i",$dateparts[1],$dateparts[0]);
  5930.         my $timerecord=((int("$yearmonthdayrecord")*100+$dateparts[3])*100+$dateparts[4])*100+$dateparts[5];
  5931.  
  5932.         # Check date
  5933.         #-----------------------
  5934.         if ($LogType eq 'M' && $timerecord > $tomorrowtime) {
  5935.             # Postfix/Sendmail does not store year, so we assume that year is year-1 if record is in future
  5936.             $yearrecord--;
  5937.             $yearmonthdayrecord=sprintf("$yearrecord%02i%02i",$dateparts[1],$dateparts[0]);
  5938.             $timerecord=((int("$yearmonthdayrecord")*100+$dateparts[3])*100+$dateparts[4])*100+$dateparts[5];
  5939.         }
  5940.         if ($timerecord < 10000000000000 || $timerecord > $tomorrowtime) {
  5941.             $NbOfLinesCorrupted++;
  5942.             if ($ShowCorrupted) { print "Corrupted record (invalid date, timerecord=$timerecord): $line\n"; }
  5943.             next;        # Should not happen, kept in case of parasite/corrupted line
  5944.         }
  5945.         if ($NewLinePhase) {
  5946. # TODO NOTSORTEDRECORDTOLERANCE does not work around midnight
  5947.             if ($timerecord < ($LastLine - $NOTSORTEDRECORDTOLERANCE)) {
  5948.                 # Should not happen, kept in case of parasite/corrupted old line
  5949.                 $NbOfLinesCorrupted++;
  5950.                 if ($ShowCorrupted) { print "Corrupted record (date $timerecord lower than $LastLine-$NOTSORTEDRECORDTOLERANCE): $line\n"; } next;
  5951.             }
  5952.         }
  5953.         else {
  5954.             if ($timerecord <= $LastLine) {    # Already processed
  5955.                 $NbOfOldLines++;
  5956.                 next;
  5957.             }
  5958.             # We found a new line. This will replace comparison "<=" with "<" between timerecord and LastLine (we should have only new lines now)
  5959.             $NewLinePhase=1;    # We will never enter here again
  5960.             if ($ShowSteps) {
  5961.                 if ($NbOfLinesShowsteps > 1 && ($NbOfLinesShowsteps & $NBOFLINESFORBENCHMARK)) {
  5962.                     my $delay=&GetDelaySinceStart(0);
  5963.                     print "".($NbOfLinesParsed-1)." lines processed (".($delay>0?$delay:1000)." ms, ".int(1000*($NbOfLinesShowsteps-1)/($delay>0?$delay:1000))." lines/second)\n";
  5964.                 }
  5965.                 &GetDelaySinceStart(1);    $NbOfLinesShowsteps=1;
  5966.             }
  5967.             if (! scalar keys %HTMLOutput) {
  5968.                 print "Phase 2 : Now process new records (Flush history on disk after ".($LIMITFLUSH<<2)." hosts)...\n";
  5969.                 #print "Phase 2 : Now process new records (Flush history on disk after ".($LIMITFLUSH<<2)." hosts or ".($LIMITFLUSH)." URLs)...\n";
  5970.             }
  5971.         }
  5972.  
  5973.         # Convert URL for Webstar to common URL
  5974.         if ($LogFormat eq '3') {
  5975.             $field[$pos_url]=~s/:/\//g;
  5976.             if ($field[$pos_code] eq '-') { $field[$pos_code]='200'; }
  5977.         }
  5978.  
  5979.         # Here, field array, timerecord and yearmonthdayrecord are initialized for log record
  5980.         if ($Debug) { debug("  This is a not already processed record ($timerecord)",4); }
  5981.  
  5982.         # We found a new line
  5983.         #----------------------------------------
  5984.         if ($timerecord > $LastLine) { $LastLine = $timerecord; }    # Test should always be true except with not sorted log files
  5985.  
  5986.         # Skip for some client host IP addresses, some URLs, other URLs
  5987.         if    (@SkipHosts && (&SkipHost($field[$pos_host]) || ($pos_hostr && &SkipHost($field[$pos_hostr]))))   { $qualifdrop="Dropped record (host $field[$pos_host]".($pos_hostr?" and $field[$pos_hostr]":"")." not qualified by SkipHosts)"; }
  5988.         elsif (@SkipFiles && &SkipFile($field[$pos_url]))    { $qualifdrop="Dropped record (URL $field[$pos_url] not qualified by SkipFiles)"; }
  5989.         elsif (@SkipUserAgents && $pos_agent >= 0 && &SkipUserAgent($field[$pos_agent]))    { $qualifdrop="Dropped record (user agent '$field[$pos_agent]' not qualified by SkipUserAgents)"; }
  5990.         elsif (@OnlyHosts && ! &OnlyHost($field[$pos_host]) && (! $pos_hostr || ! &OnlyHost($field[$pos_hostr]))) { $qualifdrop="Dropped record (host $field[$pos_host]".($pos_hostr?" and $field[$pos_hostr]":"")." not qualified by OnlyHosts)"; } 
  5991.         elsif (@OnlyFiles && ! &OnlyFile($field[$pos_url]))  { $qualifdrop="Dropped record (URL $field[$pos_url] not qualified by OnlyFiles)"; }
  5992.         elsif (@OnlyUserAgents && ! &OnlyUserAgent($field[$pos_agent]))  { $qualifdrop="Dropped record (user agent '$field[$pos_agent]' not qualified by OnlyUserAgents)"; }
  5993.         if ($qualifdrop) {
  5994.             $NbOfLinesDropped++;
  5995.             if ($Debug) { debug("$qualifdrop: $line",4); }
  5996.             if ($ShowDropped) { print "$qualifdrop: $line\n"; }
  5997.             $qualifdrop='';
  5998.             next;
  5999.         }
  6000.  
  6001.         # Record is approved
  6002.         #-------------------
  6003.  
  6004.         # Is it in a new month section ?
  6005.         #-------------------------------
  6006.         if ((($monthrecord > $lastprocessedmonth) && ($yearrecord >= $lastprocessedyear)) || ($yearrecord > $lastprocessedyear)) {
  6007.             # A new month to process
  6008.             if ($lastprocessedmonth) {
  6009.                 # We save data of processed month
  6010.                 &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line));
  6011.                 $counterforflushtest=0;    # We reset counterforflushtest
  6012.             }
  6013.             $lastprocessedyearmonth=sprintf("%04i%02i",$lastprocessedyear=$yearrecord,$lastprocessedmonth=$monthrecord);
  6014.         }
  6015.  
  6016.         $countedtraffic=0;
  6017.         $NbOfNewLines++;
  6018.  
  6019.         # Convert $field[$pos_size]
  6020.         # if ($field[$pos_size] eq '-') { $field[$pos_size]=0; }
  6021.  
  6022.         # Define a clean target URL and referrer URL
  6023.         # We keep a clean $field[$pos_url] and
  6024.         # we store original value for urlwithnoquery, tokenquery and standalonequery
  6025.         #---------------------------------------------------------------------------
  6026.         if ($URLNotCaseSensitive) { $field[$pos_url]=lc($field[$pos_url]); }
  6027.         # Possible URL syntax for $field[$pos_url]: /mydir/mypage.ext?param1=x¶m2=y#aaa, /mydir/mypage.ext#aaa, /
  6028.         my $urlwithnoquery; my $tokenquery; my $standalonequery; my $anchor='';
  6029.         if ($field[$pos_url] =~ s/$regtruncanchor//o) { $anchor=$1; }    # Remove and save anchor
  6030.         if ($URLWithQuery) {
  6031.             $urlwithnoquery=$field[$pos_url];
  6032.             my $foundparam=($urlwithnoquery =~ s/$regtruncurl//o);
  6033.             $tokenquery=$1||'';
  6034.             $standalonequery=$2||'';
  6035.             # For IIS setup, if pos_query is enabled we need to combine the URL to query strings
  6036.             if (! $foundparam && $pos_query >=0 && $field[$pos_query] && $field[$pos_query] ne '-') {
  6037.                 $foundparam=1;
  6038.                 $tokenquery='?';
  6039.                 $standalonequery=$field[$pos_query];
  6040.                 # Define query
  6041.                 $field[$pos_url] .= '?'.$field[$pos_query];
  6042.             }
  6043.              if ($foundparam) {
  6044.                 # Keep only params that are defined in URLWithQueryWithOnlyFollowingParameters
  6045.                 my $newstandalonequery='';
  6046.                 if (@URLWithQueryWithOnly) {
  6047.                     foreach (@URLWithQueryWithOnly) {
  6048.                         foreach my $p (split(/&/,$standalonequery)) {
  6049.                             if ($URLNotCaseSensitive) { if ($p =~ /^$_=/i) { $newstandalonequery.="$p&"; last; } }
  6050.                             else { if ($p =~ /^$_=/) { $newstandalonequery.="$p&"; last; } }
  6051.                         }
  6052.                     }
  6053.                      chop $newstandalonequery;
  6054.                  }
  6055.                  # Remove params that are marked to be ignored in URLWithQueryWithoutFollowingParameters
  6056.                 elsif (@URLWithQueryWithout) {
  6057.                     foreach my $p (split(/&/,$standalonequery)) {
  6058.                         my $found=0;
  6059.                         foreach (@URLWithQueryWithout) {
  6060.                             #if ($Debug) { debug("  Check if '$_=' is param '$p' to remove it from query",5); }
  6061.                             if ($URLNotCaseSensitive) { if ($p =~ /^$_=/i) { $found=1; last; } }
  6062.                             else { if ($p =~ /^$_=/) { $found=1; last; } }
  6063.                         }
  6064.                         if (! $found) { $newstandalonequery.="$p&"; }
  6065.                     }
  6066.                      chop $newstandalonequery;
  6067.                 }
  6068.                 else { $newstandalonequery=$standalonequery; }
  6069.                 # Define query
  6070.                 $field[$pos_url]=$urlwithnoquery;
  6071.                 if ($newstandalonequery) { $field[$pos_url].="$tokenquery$newstandalonequery"; }
  6072.             }
  6073.         }
  6074.         else {
  6075.             # Trunc parameters of URL
  6076.             $field[$pos_url] =~ s/$regtruncurl//o;
  6077.             $urlwithnoquery=$field[$pos_url];
  6078.             $tokenquery=$1||'';
  6079.             $standalonequery=$2||'';
  6080.             # For IIS setup, if pos_query is enabled we need to use it for query strings
  6081.             if ($pos_query >=0 && $field[$pos_query] && $field[$pos_query] ne '-') {
  6082.                 $tokenquery='?';
  6083.                 $standalonequery=$field[$pos_query];
  6084.             }
  6085.         }
  6086.         if ($URLWithAnchor && $anchor) { $field[$pos_url].="#$anchor"; }    # Restore anchor
  6087.         # Here now urlwithnoquery is /mydir/mypage.ext, /mydir, /, /page#XXX
  6088.         # Here now tokenquery is '' or '?' or ';'
  6089.         # Here now standalonequery is '' or 'param1=x'
  6090.  
  6091.         # Define page and extension
  6092.         #--------------------------
  6093.         my $PageBool=1;
  6094.         # Extension
  6095.         my $extension;
  6096.         if ($urlwithnoquery =~ /$regext/o || ($urlwithnoquery =~ /[\\\/]$/ && $DefaultFile[0] =~ /$regext/o)) {
  6097.             $extension=($LevelForFileTypesDetection>=2 || $MimeHashFamily{$1})?lc($1):'Unknown';
  6098.             if ($NotPageList{$extension}) { $PageBool=0; }
  6099.         }
  6100.         else {
  6101.             $extension='Unknown';
  6102.         }
  6103.  
  6104.         # Analyze: misc tracker (must be before return code)
  6105.         #---------------------------------------------------
  6106.         if ($urlwithnoquery =~ /$regmisc/o) {
  6107.             if ($Debug) { debug("  Found an URL that is a MiscTracker record with standalonequery=$standalonequery",2); }
  6108.             my $foundparam=0;
  6109.             foreach (split(/&/,$standalonequery)) {
  6110.                 if ($_ =~ /^screen=(\d+)x(\d+)/i)     { $foundparam++; $_screensize_h{"$1x$2"}++; next; }
  6111.                 #if ($_ =~ /cdi=(\d+)/i)             { $foundparam++; $_screendepth_h{"$1"}++; next; }
  6112.                 if ($_ =~ /^java=(\w+)/i)             { $foundparam++; if ($1 eq 'true') { $_misc_h{"JavaEnabled"}++; } next; }
  6113.                 if ($_ =~ /^shk=(\w+)/i)             { $foundparam++; if ($1 eq 'y')    { $_misc_h{"DirectorSupport"}++; } next; }
  6114.                 if ($_ =~ /^fla=(\w+)/i)             { $foundparam++; if ($1 eq 'y')    { $_misc_h{"FlashSupport"}++; } next; }
  6115.                 if ($_ =~ /^rp=(\w+)/i)                 { $foundparam++; if ($1 eq 'y')    { $_misc_h{"RealPlayerSupport"}++; } next; }
  6116.                 if ($_ =~ /^mov=(\w+)/i)             { $foundparam++; if ($1 eq 'y')    { $_misc_h{"QuickTimeSupport"}++; } next; }
  6117.                 if ($_ =~ /^wma=(\w+)/i)             { $foundparam++; if ($1 eq 'y')    { $_misc_h{"WindowsMediaPlayerSupport"}++; } next; }
  6118.                 if ($_ =~ /^pdf=(\w+)/i)             { $foundparam++; if ($1 eq 'y')    { $_misc_h{"PDFSupport"}++; } next; }
  6119.             }
  6120.             if ($foundparam) { $_misc_h{"TotalMisc"}++; }
  6121.         }
  6122.  
  6123.         # Analyze: favicon (countedtraffic=>1)
  6124.         #-------------------------------------
  6125.         if ($pos_referer >= 0 && $field[$pos_referer] && $urlwithnoquery =~ /$regfavico/o) {
  6126.             if (($field[$pos_code] != 404 || $urlwithnoquery !~ /\/.+\/favicon\.ico$/i) && ($field[$pos_agent] =~ /MSIE/)) {
  6127.                 # We don't count one hit if (not on root and error) and MSIE
  6128.                 # If error not on root, another hit will be made on root. If not MSIE, hit are made not only for "Adding".
  6129.                 $_misc_h{'AddToFavourites'}++;    # Hit on favicon on root or without error, we count it
  6130.             }
  6131.             $countedtraffic=1;    # favicon is the only case not counted anywhere
  6132.         }
  6133.  
  6134.         # Analyze: Worms (countedtraffic=>1 if worm)
  6135.         #-------------------------------------------
  6136.         if (! $countedtraffic) {
  6137.         if ($LevelForWormsDetection) {
  6138.             foreach (@WormsSearchIDOrder) {
  6139.                 if ($field[$pos_url] =~ /$_/) {
  6140.                     # It's a worm
  6141.                     my $worm=&UnCompileRegex($_);
  6142.                     if ($Debug) { debug(" Record is a hit from a worm identified by '$worm'",2); }
  6143.                     $worm=$WormsHashID{$worm}||'unknown';
  6144.                     $_worm_h{$worm}++;
  6145.                     $_worm_k{$worm}+=int($field[$pos_size]);
  6146.                     $_worm_l{$worm}=$timerecord;
  6147.                     $countedtraffic=1;
  6148.                     if ($PageBool) { $_time_nv_p[$hourrecord]++; }
  6149.                     $_time_nv_h[$hourrecord]++;
  6150.                     $_time_nv_k[$hourrecord]+=int($field[$pos_size]);
  6151.                     last;
  6152.                 }
  6153.             }
  6154.         }
  6155.         }
  6156.                     
  6157.         # Analyze: Status code (countedtraffic=>1 if error)
  6158.         #--------------------------------------------------
  6159.         if (! $countedtraffic) {
  6160.         if ($LogType eq 'W' || $LogType eq 'S') {        # HTTP record or Stream record
  6161.             if ($ValidHTTPCodes{$field[$pos_code]}) {    # Code is valid
  6162.                 if ($field[$pos_code] == 304) { $field[$pos_size]=0; }
  6163.             }
  6164.             else {                                        # Code is not valid
  6165.                 if ($field[$pos_code] !~ /^\d\d\d$/) { $field[$pos_code]=999; }
  6166.                 $_errors_h{$field[$pos_code]}++;
  6167.                 $_errors_k{$field[$pos_code]}+=int($field[$pos_size]);
  6168.                 foreach my $code (keys %TrapInfosForHTTPErrorCodes) {
  6169.                     if ($field[$pos_code] == $code) {
  6170.                         my $newurl=substr($field[$pos_url],0,$MaxLengthOfStoredURL);
  6171.                         $newurl =~ s/[$URLQuerySeparators].*$//;
  6172.                         $_sider404_h{$newurl}++;
  6173.                         my $newreferer=$field[$pos_referer];
  6174.                         if (! $URLReferrerWithQuery) { $newreferer =~ s/[$URLQuerySeparators].*$//; }
  6175.                         $_referer404_h{$newurl}=$newreferer;
  6176.                         last;
  6177.                     }
  6178.                 }
  6179.                 if ($Debug) { debug(" Record stored in the status code chart (status code=$field[$pos_code])",2); }
  6180.                 $countedtraffic=1;
  6181.                 if ($PageBool) { $_time_nv_p[$hourrecord]++; }
  6182.                 $_time_nv_h[$hourrecord]++;
  6183.                 $_time_nv_k[$hourrecord]+=int($field[$pos_size]);
  6184.             }
  6185.         }
  6186.         elsif ($LogType eq 'M') {                        # Mail record
  6187.             if (! $ValidSMTPCodes{$field[$pos_code]}) {    # Code is not valid
  6188.                 $_errors_h{$field[$pos_code]}++;
  6189.                 $_errors_k{$field[$pos_code]}+=int($field[$pos_size]);    # Size is often 0 when error
  6190.                 if ($Debug) { debug(" Record stored in the status code chart (status code=$field[$pos_code])",2); }
  6191.                 $countedtraffic=1;
  6192.                 if ($PageBool) { $_time_nv_p[$hourrecord]++; }
  6193.                 $_time_nv_h[$hourrecord]++;
  6194.                 $_time_nv_k[$hourrecord]+=int($field[$pos_size]);
  6195.             }
  6196.         }
  6197.         elsif ($LogType eq 'F') {                        # FTP record
  6198.         }
  6199.         }
  6200.         
  6201.         # Analyze: Robot from robot database (countedtraffic=>1 if robot)
  6202.         #----------------------------------------------------------------
  6203.         if (! $countedtraffic) {
  6204.         if ($pos_agent >= 0) {
  6205.             if ($DecodeUA) { $field[$pos_agent] =~ s/%20/_/g; }    # This is to support servers (like Roxen) that writes user agent with %20 in it
  6206.             $UserAgent=$field[$pos_agent];
  6207.  
  6208.             if ($LevelForRobotsDetection) {
  6209.  
  6210.                 my $uarobot=$TmpRobot{$UserAgent};
  6211.                 if (! $uarobot) {
  6212.                     #study $UserAgent;        Does not increase speed
  6213.                     foreach (@RobotsSearchIDOrder) {
  6214.                         if ($UserAgent =~ /$_/) {
  6215.                             my $bot=&UnCompileRegex($_);
  6216.                             $TmpRobot{$UserAgent}=$uarobot="$bot";    # Last time, we won't search if robot or not. We know it is.
  6217.                             if ($Debug) { debug("  UserAgent '$UserAgent' is added to TmpRobot with value '$bot'",2); }
  6218.                             last;
  6219.                         }
  6220.                     }
  6221.                     if (! $uarobot) {                                # Last time, we won't search if robot or not. We know it's not.
  6222.                         $TmpRobot{$UserAgent}=$uarobot='-';
  6223.                     }
  6224.                 }
  6225.                 if ($uarobot ne '-') {
  6226.                     # If robot, we stop here
  6227.                     if ($Debug) { debug("  UserAgent '$UserAgent' contains robot ID '$uarobot'",2); }
  6228.                     $_robot_h{$uarobot}++;
  6229.                     $_robot_k{$uarobot}+=int($field[$pos_size]);
  6230.                     $_robot_l{$uarobot}=$timerecord;
  6231.                     if ($urlwithnoquery =~ /$regrobot/o) { $_robot_r{$uarobot}++; }
  6232.                     $countedtraffic=1;
  6233.                     if ($PageBool) { $_time_nv_p[$hourrecord]++; }
  6234.                     $_time_nv_h[$hourrecord]++;
  6235.                     $_time_nv_k[$hourrecord]+=int($field[$pos_size]);
  6236.                 }
  6237.             }
  6238.         }
  6239.         }
  6240.  
  6241.         # Analyze: Robot from "hit on robots.txt" file (countedtraffic=>1 if robot)
  6242.         # -------------------------------------------------------------------------
  6243.         if (! $countedtraffic) {
  6244.         if ($urlwithnoquery =~ /$regrobot/o) {
  6245.             if ($Debug) { debug("  It's an unknown robot",2); }
  6246.             $_robot_h{'unknown'}++;
  6247.             $_robot_k{'unknown'}+=int($field[$pos_size]);
  6248.             $_robot_l{'unknown'}=$timerecord;
  6249.             $_robot_r{'unknown'}++;
  6250.             $countedtraffic=1;
  6251.             if ($PageBool) { $_time_nv_p[$hourrecord]++; }
  6252.             $_time_nv_h[$hourrecord]++;
  6253.             $_time_nv_k[$hourrecord]+=int($field[$pos_size]);
  6254.         }
  6255.         }
  6256.         
  6257.         # Analyze: File type - Compression
  6258.         #---------------------------------
  6259.         if (! $countedtraffic) {
  6260.         if ($LevelForFileTypesDetection) {
  6261.             $_filetypes_h{$extension}++;
  6262.             $_filetypes_k{$extension}+=int($field[$pos_size]);    # TODO can cause a warning
  6263.             # Compression
  6264.             if ($pos_gzipin>=0 && $field[$pos_gzipin]) {                        # If in and out in log
  6265.                 my ($notused,$in)=split(/:/,$field[$pos_gzipin]);
  6266.                 my ($notused1,$out,$notused2)=split(/:/,$field[$pos_gzipout]);
  6267.                 if ($out) {
  6268.                     $_filetypes_gz_in{$extension}+=$in;
  6269.                     $_filetypes_gz_out{$extension}+=$out;
  6270.                 }
  6271.             }
  6272.             elsif ($pos_compratio>=0 && ($field[$pos_compratio] =~ /(\d+)/)) {     # Calculate in/out size from percentage
  6273.                 if ($fieldlib[$pos_compratio] eq 'gzipratio') {
  6274.                     # with mod_gzip:    % is size (before-after)/before (low for jpg) ??????????
  6275.                     $_filetypes_gz_in{$extension}+=int($field[$pos_size]*100/((100-$1)||1));
  6276.                 } else {
  6277.                     # with mod_deflate: % is size after/before (high for jpg)
  6278.                     $_filetypes_gz_in{$extension}+=int($field[$pos_size]*100/($1||1));
  6279.                 }
  6280.                 $_filetypes_gz_out{$extension}+=int($field[$pos_size]);
  6281.             }
  6282.         }
  6283.  
  6284.         # Analyze: Date - Hour - Pages - Hits - Kilo
  6285.         #-------------------------------------------
  6286.         if ($PageBool) {
  6287.             # Replace default page name with / only ('if' is to increase speed when only 1 value in @DefaultFile)
  6288.             if (@DefaultFile > 1) { foreach my $elem (@DefaultFile) { if ($field[$pos_url] =~ s/\/$elem$/\//o) { last; } } }
  6289.             else { $field[$pos_url] =~ s/$regdefault/\//o; }
  6290.             # FirstTime and LastTime are First and Last human visits (so changed if access to a page)
  6291.             $FirstTime{$lastprocessedyearmonth}||=$timerecord;
  6292.             $LastTime{$lastprocessedyearmonth}=$timerecord;
  6293.             $DayPages{$yearmonthdayrecord}++;
  6294. #            $MonthPages{$lastprocessedyearmonth}++;
  6295.             $_url_p{$field[$pos_url]}++;                                         #Count accesses for page (page)
  6296.             $_url_k{$field[$pos_url]}+=int($field[$pos_size]);
  6297.             $_time_p[$hourrecord]++;                                            #Count accesses for hour (page)
  6298.         }
  6299.         $_time_h[$hourrecord]++;
  6300.         $_time_k[$hourrecord]+=int($field[$pos_size]);
  6301.          $DayHits{$yearmonthdayrecord}++;                        #Count accesses for hour (hit)
  6302.          $DayBytes{$yearmonthdayrecord}+=int($field[$pos_size]);    #Count accesses for hour (kb)
  6303. #        $MonthHits{$lastprocessedyearmonth}++;
  6304. #        $MonthBytes{$lastprocessedyearmonth}+=int($field[$pos_size]);
  6305.  
  6306.         # Analyze: Login
  6307.         #---------------
  6308.         if ($pos_logname>=0 && $field[$pos_logname] && $field[$pos_logname] ne '-') {
  6309.             $field[$pos_logname] =~ s/ /_/g; # This is to allow space in logname
  6310.             if ($LogFormat eq '6') { $field[$pos_logname] =~ s/^\"//; $field[$pos_logname] =~ s/\"$//;}    # logname field has " with Domino 6+
  6311.             if ($AuthenticatedUsersNotCaseSensitive) { $field[$pos_logname]=lc($field[$pos_logname]); }
  6312.  
  6313.             # We found an authenticated user
  6314.             if ($PageBool) { $_login_p{$field[$pos_logname]}++; }                #Count accesses for page (page)
  6315.             $_login_h{$field[$pos_logname]}++;                                    #Count accesses for page (hit)
  6316.             $_login_k{$field[$pos_logname]}+=int($field[$pos_size]);            #Count accesses for page (kb)
  6317.             $_login_l{$field[$pos_logname]}=$timerecord;
  6318.         }
  6319.         }
  6320.         
  6321.         # Do DNS lookup
  6322.         #--------------
  6323.         my $Host=$field[$pos_host];
  6324.         my $HostResolved='';
  6325.  
  6326.         if (! $countedtraffic) {
  6327.         my $ip=0;
  6328.         if ($DNSLookup) {            # DNS lookup is 1 or 2
  6329.             if ($Host =~ /$regipv4/o) { $ip=4; }    # IPv4
  6330.             elsif ($Host =~ /$regipv6/o) { $ip=6; }                        # IPv6
  6331.             if ($ip) {
  6332.                 # Check in static DNS cache file
  6333.                 $HostResolved=$MyDNSTable{$Host};
  6334.                 if ($HostResolved) {
  6335.                     if ($Debug) { debug("  DNS lookup asked for $Host and found in static DNS cache file: $HostResolved",4); }
  6336.                 }
  6337.                 elsif ($DNSLookup==1) {
  6338.                     # Check in session cache (dynamic DNS cache file + session DNS cache)
  6339.                     $HostResolved=$TmpDNSLookup{$Host};
  6340.                     if (! $HostResolved) {
  6341.                         if (@SkipDNSLookupFor && &SkipDNSLookup($Host)) {
  6342.                             $HostResolved=$TmpDNSLookup{$Host}='*';
  6343.                             if ($Debug) { debug("  No need of reverse DNS lookup for $Host, skipped at user request.",4); }
  6344.                         }
  6345.                         else {
  6346.                             if ($ip == 4) {
  6347.                                 my $lookupresult=gethostbyaddr(pack("C4",split(/\./,$Host)),AF_INET);    # This is very slow, may spend 20 seconds
  6348.                                 if (! $lookupresult || $lookupresult =~ /$regipv4/o || ! IsAscii($lookupresult)) {
  6349.                                     $TmpDNSLookup{$Host}=$HostResolved='*';
  6350.                                 }
  6351.                                 else {
  6352.                                     $TmpDNSLookup{$Host}=$HostResolved=$lookupresult;
  6353.                                 }
  6354.                                 if ($Debug) { debug("  Reverse DNS lookup for $Host done: $HostResolved",4); }
  6355.                             }
  6356.                             elsif ($ip == 6) {
  6357.                                 if ($PluginsLoaded{'GetResolvedIP'}{'ipv6'}) {
  6358.                                     my $lookupresult=GetResolvedIP_ipv6($Host);
  6359.                                     if (! $lookupresult || ! IsAscii($lookupresult)) {
  6360.                                         $TmpDNSLookup{$Host}=$HostResolved='*';
  6361.                                     }
  6362.                                     else {
  6363.                                         $TmpDNSLookup{$Host}=$HostResolved=$lookupresult;
  6364.                                     }
  6365.                                 } else {
  6366.                                     $TmpDNSLookup{$Host}=$HostResolved='*';
  6367.                                     warning("Reverse DNS lookup for $Host not available without ipv6 plugin enabled.");
  6368.                                 }
  6369.                             }
  6370.                             else { error("Bad value vor ip"); }
  6371.                         }
  6372.                     }
  6373.                 }
  6374.                 else {
  6375.                     $HostResolved='*';
  6376.                     if ($Debug) { debug("  DNS lookup by static DNS cache file asked for $Host but not found.",4); }
  6377.                 }
  6378.             }
  6379.             else {
  6380.                 if ($Debug) { debug("  DNS lookup asked for $Host but this is not an IP address.",4); }
  6381.                 $DNSLookupAlreadyDone=$LogFile;
  6382.             }
  6383.         }
  6384.         else {
  6385.             if ($Host =~ /$regipv4/o) { $HostResolved='*'; $ip=4; }    # IPv4
  6386.             elsif ($Host =~ /$regipv6/o) { $HostResolved='*'; $ip=6; }                        # IPv6
  6387.             if ($Debug) { debug("  No DNS lookup asked.",4); }
  6388.         }
  6389.  
  6390.         # Analyze: Country (Top-level domain)
  6391.         #------------------------------------
  6392.         if ($Debug) { debug("  Search country (Host=$Host HostResolved=$HostResolved ip=$ip)",4); }
  6393.         my $Domain='ip';
  6394.         # Set $HostResolved to host and resolve domain
  6395.         if ($HostResolved eq '*') {
  6396.             # $Host is an IP address and is not resolved (failed or not asked) or resolution gives an IP address
  6397.             $HostResolved = $Host;
  6398.             # Resolve Domain
  6399.             if ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'}) { $Domain=GetCountryCodeByAddr_geoipfree($HostResolved); }
  6400.             elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'}) { $Domain=GetCountryCodeByAddr_geoip($HostResolved); }
  6401.         }
  6402.         else {
  6403.             # $Host was already a host name ($Host=name => $HostResolved='', $ip=0) or has been resolved ($Host=ip => $HostResolved defined, $ip>0)
  6404.             $HostResolved = lc($HostResolved?$HostResolved:$Host);
  6405.             # Resolve Domain
  6406.             if ($ip) {
  6407.                 if ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoipfree'}) { $Domain=GetCountryCodeByAddr_geoipfree($Host); }
  6408.                 elsif ($PluginsLoaded{'GetCountryCodeByAddr'}{'geoip'}) { $Domain=GetCountryCodeByAddr_geoip($Host); }
  6409.                 elsif ($HostResolved =~ /\.(\w+)$/) { $Domain=$1; }
  6410.             }
  6411.             else {
  6412.                 if ($PluginsLoaded{'GetCountryCodeByName'}{'geoipfree'}) { $Domain=GetCountryCodeByName_geoipfree($HostResolved); }
  6413.                 elsif ($PluginsLoaded{'GetCountryCodeByName'}{'geoip'}) { $Domain=GetCountryCodeByName_geoip($HostResolved); }
  6414.                 elsif ($HostResolved =~ /\.(\w+)$/) { $Domain=$1; }
  6415.             }
  6416.         }
  6417.         # Store country
  6418.         if ($PageBool) { $_domener_p{$Domain}++; }
  6419.         $_domener_h{$Domain}++;
  6420.         $_domener_k{$Domain}+=int($field[$pos_size]);
  6421.  
  6422.         # Analyze: Host, URL and Session
  6423.         #-------------------------------
  6424.         if ($PageBool) {
  6425.             my $timehostl=$_host_l{$HostResolved};
  6426.             if ($timehostl) {
  6427.                 # A visit for this host was already detected
  6428. # TODO everywhere there is $VISITTIMEOUT
  6429. #                $timehostl =~ /^\d\d\d\d\d\d(\d\d)/; my $daytimehostl=$1;
  6430. #                if ($timerecord > ($timehostl+$VISITTIMEOUT+($dateparts[3]>$daytimehostl?$NEWDAYVISITTIMEOUT:0))) {
  6431.                 if ($timerecord > ($timehostl+$VISITTIMEOUT)) {
  6432.                     # This is a second visit or more
  6433.                     if (! $_waithost_s{$HostResolved}) {
  6434.                         # This is a second visit or more
  6435.                         # We count 'visit','exit','entry','DayVisits'
  6436.                         if ($Debug) { debug("  This is a second visit for $HostResolved.",4); }
  6437.                         my $timehosts=$_host_s{$HostResolved};
  6438.                         my $page=$_host_u{$HostResolved};
  6439.                         if ($page) { $_url_x{$page}++; }
  6440.                         $_url_e{$field[$pos_url]}++;
  6441.                         $DayVisits{$yearmonthdayrecord}++;
  6442.                         # We can't count session yet because we don't have the start so
  6443.                         # we save params of first 'wait' session
  6444.                         $_waithost_l{$HostResolved}=$timehostl;
  6445.                         $_waithost_s{$HostResolved}=$timehosts;
  6446.                         $_waithost_u{$HostResolved}=$page;
  6447.                     }
  6448.                     else {
  6449.                         # This is third visit or more
  6450.                         # We count 'session','visit','exit','entry','DayVisits'
  6451.                         if ($Debug) { debug("  This is a third visit or more for $HostResolved.",4); }
  6452.                         my $timehosts=$_host_s{$HostResolved};
  6453.                         my $page=$_host_u{$HostResolved};
  6454.                         if ($page) { $_url_x{$page}++; }
  6455.                         $_url_e{$field[$pos_url]}++;
  6456.                         $DayVisits{$yearmonthdayrecord}++;
  6457.                         if ($timehosts) { $_session{GetSessionRange($timehosts,$timehostl)}++; }
  6458.                     }
  6459.                     # Save new session properties
  6460.                     $_host_s{$HostResolved}=$timerecord;
  6461.                     $_host_l{$HostResolved}=$timerecord;
  6462.                     $_host_u{$HostResolved}=$field[$pos_url];
  6463.                 }
  6464.                 elsif ($timerecord > $timehostl) {
  6465.                     # This is a same visit we can count
  6466.                     if ($Debug) { debug("  This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",4); }
  6467.                     $_host_l{$HostResolved}=$timerecord;
  6468.                     $_host_u{$HostResolved}=$field[$pos_url];
  6469.                 }
  6470.                 elsif ($timerecord == $timehostl) {
  6471.                     # This is a same visit we can count
  6472.                     if ($Debug) { debug("  This is same visit still running for $HostResolved. host_l/host_u changed to $timerecord/$field[$pos_url]",4); }
  6473.                     $_host_u{$HostResolved}=$field[$pos_url];
  6474.                 }
  6475.                 elsif ($timerecord < $_host_s{$HostResolved}) {
  6476.                     # Should happens only with not correctly sorted log files
  6477.                     if ($Debug) { debug("  This is same visit still running for $HostResolved with start not in order. host_s changed to $timerecord (entry page also changed if first visit)",4); }
  6478.                     if (! $_waithost_s{$HostResolved}) {
  6479.                         # We can reorder entry page only if it's the first visit found in this update run (The saved entry page was $_waithost_e if $_waithost_s{$HostResolved} is not defined. If second visit or more, entry was directly counted and not saved)
  6480.                         $_waithost_e{$HostResolved}=$field[$pos_url];
  6481.                     }
  6482.                     else {
  6483.                         # We can't change entry counted as we dont't know what was the url counted as entry
  6484.                     }
  6485.                     $_host_s{$HostResolved}=$timerecord;
  6486.                 }
  6487.                 else {
  6488.                     if ($Debug) { debug("  This is same visit still running for $HostResolved with hit between start and last hits. No change",4); }
  6489.                 }
  6490.             }
  6491.             else {
  6492.                 # This is a new visit (may be). First new visit found for this host. We save in wait array the entry page to count later
  6493.                 if ($Debug) { debug("  New session (may be) for $HostResolved. Save in wait array to see later",4); }
  6494.                 $_waithost_e{$HostResolved}=$field[$pos_url];
  6495.                 # Save new session properties
  6496.                 $_host_u{$HostResolved}=$field[$pos_url];
  6497.                 $_host_s{$HostResolved}=$timerecord;
  6498.                 $_host_l{$HostResolved}=$timerecord;
  6499.             }
  6500.             $_host_p{$HostResolved}++;
  6501.         }
  6502.         $_host_h{$HostResolved}++;
  6503.         $_host_k{$HostResolved}+=int($field[$pos_size]);
  6504.  
  6505.         # Analyze: Browser - OS
  6506.         #----------------------
  6507.         if ($pos_agent >= 0 && $UserAgent) {
  6508.  
  6509.             if ($LevelForBrowsersDetection) {
  6510.  
  6511.                 # Analyze: Browser
  6512.                 #-----------------
  6513.                 my $uabrowser=$TmpBrowser{$UserAgent};
  6514.                 if (! $uabrowser) {
  6515.                     my $found=1;
  6516.                     # IE ?
  6517.                     if ($UserAgent =~ /$regvermsie/o && $UserAgent !~ /$regnotie/o) {
  6518.                         $_browser_h{"msie$2"}++;
  6519.                         $TmpBrowser{$UserAgent}="msie$2";
  6520.                     }
  6521.                     # Netscape 6.x, 7.x ... ?
  6522.                     elsif ($UserAgent =~ /$regvernetscape/o) {
  6523.                         $_browser_h{"netscape$1"}++;
  6524.                         $TmpBrowser{$UserAgent}="netscape$1";
  6525.                     }
  6526.                     # Netscape 3.x, 4.x ... ?
  6527.                     elsif ($UserAgent =~ /$regvermozilla/o && $UserAgent !~ /$regnotnetscape/o) {
  6528.                         $_browser_h{"netscape$2"}++;
  6529.                         $TmpBrowser{$UserAgent}="netscape$2";
  6530.                     }
  6531.                     # Other known browsers ?
  6532.                     else {
  6533.                         $found=0;
  6534.                         foreach (@BrowsersSearchIDOrder) {    # Search ID in order of BrowsersSearchIDOrder
  6535.                             if ($UserAgent =~ /$_/) {
  6536.                                 my $browser=&UnCompileRegex($_);
  6537.                                 # TODO If browser is in a family, use version
  6538.                                 $_browser_h{"$browser"}++;
  6539.                                 $TmpBrowser{$UserAgent}="$browser";
  6540.                                 $found=1;
  6541.                                 last;
  6542.                             }
  6543.                         }
  6544.                     }
  6545.                     # Unknown browser ?
  6546.                     if (!$found) {
  6547.                         $_browser_h{'Unknown'}++;
  6548.                         $TmpBrowser{$UserAgent}='Unknown';
  6549.                         my $newua=$UserAgent; $newua =~ tr/\+ /__/;
  6550.                         $_unknownrefererbrowser_l{$newua}=$timerecord;
  6551.                     }
  6552.                 }
  6553.                 else {
  6554.                     $_browser_h{$uabrowser}++;
  6555.                     if ($uabrowser eq 'Unknown') {
  6556.                         my $newua=$UserAgent; $newua =~ tr/\+ /__/;
  6557.                         $_unknownrefererbrowser_l{$newua}=$timerecord;
  6558.                     }
  6559.                 }
  6560.  
  6561.             }
  6562.  
  6563.             if ($LevelForOSDetection) {
  6564.  
  6565.                 # Analyze: OS
  6566.                 #------------
  6567.                 my $uaos=$TmpOS{$UserAgent};
  6568.                 if (! $uaos) {
  6569.                     my $found=0;
  6570.                     # in OSHashID list ?
  6571.                     foreach (@OSSearchIDOrder) {    # Search ID in order of OSSearchIDOrder
  6572.                         if ($UserAgent =~ /$_/) {
  6573.                             my $osid=$OSHashID{&UnCompileRegex($_)};
  6574.                             $_os_h{"$osid"}++;
  6575.                             $TmpOS{$UserAgent}="$osid";
  6576.                             $found=1;
  6577.                             last;
  6578.                         }
  6579.                     }
  6580.                     # Unknown OS ?
  6581.                     if (!$found) {
  6582.                         $_os_h{'Unknown'}++;
  6583.                         $TmpOS{$UserAgent}='Unknown';
  6584.                         my $newua=$UserAgent; $newua =~ tr/\+ /__/;
  6585.                         $_unknownreferer_l{$newua}=$timerecord;
  6586.                     }
  6587.                 }
  6588.                 else {
  6589.                     $_os_h{$uaos}++;
  6590.                     if ($uaos eq 'Unknown') {
  6591.                         my $newua=$UserAgent; $newua =~ tr/\+ /__/;
  6592.                         $_unknownreferer_l{$newua}=$timerecord;
  6593.                     }
  6594.                 }
  6595.  
  6596.             }
  6597.  
  6598.         }
  6599.         else {
  6600.             $_browser_h{'Unknown'}++;
  6601.             $_os_h{'Unknown'}++;
  6602.         }
  6603.  
  6604.         # Analyze: Referer
  6605.         #-----------------
  6606.         my $found=0;
  6607.         if ($pos_referer >= 0 && $LevelForRefererAnalyze && $field[$pos_referer]) {
  6608.  
  6609.             # Direct ?
  6610.             if ($field[$pos_referer] eq '-' || $field[$pos_referer] eq 'bookmarks') {    # "bookmarks" is sent by Netscape, '-' by all others browsers
  6611.                 # Direct access
  6612.                 if ($PageBool) { $_from_p[0]++; }
  6613.                 $_from_h[0]++;
  6614.                 $found=1;
  6615.             }
  6616.             else {
  6617.                 $field[$pos_referer] =~ /$regreferer/o;
  6618.                 my $refererprot=$1;
  6619.                 my $refererserver=($2||'').(! $3 || $3 eq ':80'?'':$3);    # refererserver is www.xxx.com or www.xxx.com:81 but not www.xxx.com:80
  6620.                 # HTML link ?
  6621.                 if ($refererprot =~ /^http/i) {
  6622.                     #if ($Debug) { debug("  Analyze referer refererprot=$refererprot refererserver=$refererserver",5); }
  6623.  
  6624.                     # Kind of origin
  6625.                     if (!$TmpRefererServer{$refererserver}) {    # is "=" if same site, "search egine key" if search engine, not defined otherwise
  6626.                         if ($refererserver =~ /$reglocal/o) {
  6627.                             # Intern (This hit came from another page of the site)
  6628.                             if ($Debug) { debug("  Server '$refererserver' is added to TmpRefererServer with value '='",2); }
  6629.                             $TmpRefererServer{$refererserver}='=';
  6630.                             $found=1;
  6631.                         }
  6632.                         else {
  6633.                             foreach (@HostAliases) {
  6634.                                 if ($refererserver =~ /$_/) {
  6635.                                     # Intern (This hit came from another page of the site)
  6636.                                     if ($Debug) { debug("  Server '$refererserver' is added to TmpRefererServer with value '='",2); }
  6637.                                     $TmpRefererServer{$refererserver}='=';
  6638.                                     $found=1;
  6639.                                     last;
  6640.                                 }
  6641.                             }
  6642.                             if (! $found) {
  6643.                                 # Extern (This hit came from an external web site).
  6644.     
  6645.                                 if ($LevelForSearchEnginesDetection) {
  6646.     
  6647.                                     foreach (@SearchEnginesSearchIDOrder) {        # Search ID in order of SearchEnginesSearchIDOrder
  6648.                                         if ($refererserver =~ /$_/) {
  6649.                                             my $key=&UnCompileRegex($_);
  6650.                                             if (! $NotSearchEnginesKeys{$key} || $refererserver !~ /$NotSearchEnginesKeys{$key}/i) {
  6651.                                                 # This hit came from the search engine $key
  6652.                                                 if ($Debug) { debug("  Server '$refererserver' is added to TmpRefererServer with value '$key'",2); }
  6653.                                                 $TmpRefererServer{$refererserver}=$SearchEnginesHashID{$key};
  6654.                                                 $found=1;
  6655.                                             }
  6656.                                             last;
  6657.                                         }
  6658.                                     }
  6659.  
  6660.                                 }
  6661.                             }
  6662.                         }
  6663.                     }
  6664.  
  6665.                     if ($TmpRefererServer{$refererserver}) {
  6666.                         if ($TmpRefererServer{$refererserver} eq '=') {
  6667.                             # Intern (This hit came from another page of the site)
  6668.                             if ($PageBool) { $_from_p[4]++; }
  6669.                             $_from_h[4]++;
  6670.                             $found=1;
  6671.                         }
  6672.                         else {
  6673.                             # This hit came from a search engine
  6674.                             if ($PageBool) { $_from_p[2]++; $_se_referrals_p{$TmpRefererServer{$refererserver}}++; }
  6675.                             $_from_h[2]++;
  6676.                             $_se_referrals_h{$TmpRefererServer{$refererserver}}++;
  6677.                             $found=1;
  6678.                             if ($PageBool && $LevelForKeywordsDetection) {
  6679.                                 # we will complete %_keyphrases hash array
  6680.                                 my @refurl=split(/\?/,$field[$pos_referer],2);    # TODO Use \? or [$URLQuerySeparators] ?
  6681.                                 if ($refurl[1]) {
  6682.                                     # Extract params of referer query string (q=cache:mmm:www/zzz+aaa+bbb q=aaa+bbb/ccc key=ddd%20eee lang_en ie=UTF-8 ...)
  6683.                                     if ($SearchEnginesKnownUrl{$TmpRefererServer{$refererserver}}) {    # Search engine with known URL syntax
  6684.                                         my @paramlist=split(/&/,$KeyWordsNotSensitive?lc($refurl[1]):$refurl[1]);
  6685.                                         foreach my $param (@paramlist) {
  6686.                                             if ($param =~ s/^$SearchEnginesKnownUrl{$TmpRefererServer{$refererserver}}//) {
  6687.                                                 # We found good parameter
  6688.                                                 # Now param is keyphrase: "cache:mmm:www/zzz+aaa+bbb/ccc+ddd%20eee'fff,ggg"
  6689.                                                 $param =~ s/^(cache|related):[^\+]+//;    # Should ne useless since this is for hit on 'not pages'
  6690.                                                 &ChangeWordSeparatorsIntoSpace($param);    # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg]
  6691.                                                 $param =~ s/^ +//; $param =~ s/ +$//; $param =~ tr/ /\+/s;
  6692.                                                 if ((length $param) > 0) { $_keyphrases{$param}++; }
  6693.                                                 last;
  6694.                                             }
  6695.                                         }
  6696.                                     }
  6697.                                     elsif ($LevelForKeywordsDetection >= 2) {                            # Search engine with unknown URL syntax
  6698.                                         my @paramlist=split(/&/,$KeyWordsNotSensitive?lc($refurl[1]):$refurl[1]);
  6699.                                         foreach my $param (@paramlist) {
  6700.                                             my $foundexcludeparam=0;
  6701.                                             foreach my $paramtoexclude (@WordsToCleanSearchUrl) {
  6702.                                                 if ($param =~ /$paramtoexclude/i) { $foundexcludeparam=1; last; } # Not the param with search criteria
  6703.                                             }
  6704.                                             if ($foundexcludeparam) { next; }
  6705.                                             # We found good parameter
  6706.                                             $param =~ s/.*=//;
  6707.                                             # Now param is keyphrase: "aaa+bbb/ccc+ddd%20eee'fff,ggg"
  6708.                                             $param =~ s/^(cache|related):[^\+]+//;        # Should ne useless since this is for hit on 'not pages'
  6709.                                             &ChangeWordSeparatorsIntoSpace($param);        # Change [ aaa+bbb/ccc+ddd%20eee'fff,ggg ] into [ aaa bbb/ccc ddd eee fff ggg ]
  6710.                                             $param =~ s/^ +//; $param =~ s/ +$//; $param =~ tr/ /\+/s;
  6711.                                             if ((length $param) > 2) { $_keyphrases{$param}++; last; }
  6712.                                         }
  6713.                                     }
  6714.                                 }    # End of if refurl[1]
  6715.                             }
  6716.                         }
  6717.                     }    # End of if ($TmpRefererServer)
  6718.                     else {
  6719.                         # This hit came from a site other than a search engine
  6720.                         if ($PageBool) { $_from_p[3]++; }
  6721.                         $_from_h[3]++;
  6722.                         # http://www.mysite.com/ must be same referer than http://www.mysite.com but .../mypage/ differs of .../mypage
  6723.                         #if ($refurl[0] =~ /^[^\/]+\/$/) { $field[$pos_referer] =~ s/\/$//; }    # Code moved in Save_History
  6724.                         # TODO: lowercase the value for referer server to have refering server not case sensitive
  6725.                         if ($URLReferrerWithQuery) {
  6726.                             if ($PageBool) { $_pagesrefs_p{$field[$pos_referer]}++; }
  6727.                             $_pagesrefs_h{$field[$pos_referer]}++;
  6728.                         }
  6729.                         else {
  6730.                             # We discard query for referer
  6731.                             if ($field[$pos_referer]=~/$regreferernoquery/o) {
  6732.                                 if ($PageBool) { $_pagesrefs_p{"$1"}++; }
  6733.                                 $_pagesrefs_h{"$1"}++;
  6734.                             }
  6735.                             else {
  6736.                                 if ($PageBool) { $_pagesrefs_p{$field[$pos_referer]}++; }
  6737.                                 $_pagesrefs_h{$field[$pos_referer]}++;
  6738.                             }
  6739.                         }
  6740.                         $found=1;
  6741.                     }
  6742.                 }
  6743.  
  6744.                 # News Link ?
  6745.                 if (! $found && $refererprot =~ /^news/i) {
  6746.                     $found=1;
  6747.                     if ($PageBool) { $_from_p[5]++; }
  6748.                     $_from_h[5]++;
  6749.                 }
  6750.             }
  6751.         }
  6752.  
  6753.         # Origin not found
  6754.         if (!$found) {
  6755.             if ($ShowUnknownOrigin) { print "Unknown origin: $field[$pos_referer]\n"; }
  6756.             if ($PageBool) { $_from_p[1]++; }
  6757.             $_from_h[1]++;
  6758.         }
  6759.  
  6760.         # Analyze: EMail
  6761.         #---------------
  6762.         if ($pos_emails>=0 && $field[$pos_emails]) {
  6763.             if ($field[$pos_emails] eq '<>') { $field[$pos_emails]='Unknown'; }
  6764.             elsif ($field[$pos_emails] !~ /\@/) { $field[$pos_emails].="\@$SiteDomain"; }
  6765.             $_emails_h{lc($field[$pos_emails])}++;                                    #Count accesses for sender email (hit)
  6766.             $_emails_k{lc($field[$pos_emails])}+=int($field[$pos_size]);            #Count accesses for sender email (kb)
  6767.             $_emails_l{lc($field[$pos_emails])}=$timerecord;
  6768.         }
  6769.         if ($pos_emailr>=0 && $field[$pos_emailr]) {
  6770.             if ($field[$pos_emailr] !~ /\@/) { $field[$pos_emailr].="\@$SiteDomain"; }
  6771.             $_emailr_h{lc($field[$pos_emailr])}++;                                    #Count accesses for receiver email (hit)
  6772.             $_emailr_k{lc($field[$pos_emailr])}+=int($field[$pos_size]);            #Count accesses for receiver email (kb)
  6773.             $_emailr_l{lc($field[$pos_emailr])}=$timerecord;
  6774.         }
  6775.         }
  6776.  
  6777.         # Check cluster
  6778.         #--------------
  6779.         if ($pos_cluster>=0) {
  6780.             if ($PageBool) { $_cluster_p{$field[$pos_cluster]}++; }                #Count accesses for page (page)
  6781.             $_cluster_h{$field[$pos_cluster]}++;                                #Count accesses for page (hit)
  6782.             $_cluster_k{$field[$pos_cluster]}+=int($field[$pos_size]);            #Count accesses for page (kb)
  6783.         }
  6784.  
  6785.         # Analyze: Extra
  6786.         #---------------
  6787.          foreach my $extranum (1..@ExtraName-1) {
  6788.             if ($Debug) { debug("  Process extra analyze $extranum",4); }
  6789.  
  6790.              # Check code
  6791.              my $conditionok=0;
  6792.              foreach my $condnum (0..@{$ExtraCodeFilter[$extranum]}-1) {
  6793.                 if ($Debug) { debug("  Check code '$field[$pos_code]' must be '$ExtraCodeFilter[$extranum][$condnum]'",5); }
  6794.                 if ($field[$pos_code] eq "$ExtraCodeFilter[$extranum][$condnum]") { $conditionok=1; last; }
  6795.             }
  6796.             if (! $conditionok && @{$ExtraCodeFilter[$extranum]}) { next; }    # End for this section
  6797.             if ($Debug) { debug("  No check on code or code is OK. Now we check other conditions.",5); }
  6798.  
  6799.              # Check conditions
  6800.              $conditionok=0;
  6801.              foreach my $condnum (0..@{$ExtraConditionType[$extranum]}-1) {
  6802.                  my $conditiontype=$ExtraConditionType[$extranum][$condnum];
  6803.                  my $conditiontypeval=$ExtraConditionTypeVal[$extranum][$condnum];
  6804.                  if ($conditiontype eq 'URL') {
  6805.                     if ($Debug) { debug("  Check condition '$conditiontype' must contain '$conditiontypeval' in '$urlwithnoquery'",5); }
  6806.                      if ($urlwithnoquery =~ /$conditiontypeval/) { $conditionok=1; last; }
  6807.                  }
  6808.                  elsif ($conditiontype eq 'QUERY_STRING') {
  6809.                     if ($Debug) { debug("  Check condition '$conditiontype' must contain '$conditiontypeval' in '$standalonequery'",5); }
  6810.                      if ($standalonequery =~ /$conditiontypeval/) {    $conditionok=1; last; }
  6811.                  }
  6812.                  elsif ($conditiontype eq 'REFERER') {
  6813.                     if ($Debug) { debug("  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_referer]'",5); }
  6814.                      if ($field[$pos_referer] =~ /$conditiontypeval/) { $conditionok=1; last; }
  6815.                  }
  6816.                  elsif ($conditiontype eq 'UA') {
  6817.                     if ($Debug) { debug("  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_agent]'",5); }
  6818.                      if ($field[$pos_agent] =~ /$conditiontypeval/) { $conditionok=1; last; }
  6819.                  }
  6820.                  elsif ($conditiontype eq 'HOST') {
  6821.                     if ($Debug) { debug("  Check condition '$conditiontype' must contain '$conditiontypeval' in '$field[$pos_host]'",5); }
  6822.                      if ($HostResolved =~ /$conditiontypeval/) { $conditionok=1; last; }
  6823.                  }
  6824.                  else { error("Wrong value of parameter ExtraSectionCondition$extranum"); }
  6825.              }
  6826.             if (! $conditionok && @{$ExtraConditionType[$extranum]}) { next; }    # End for this section
  6827.             if ($Debug) { debug("  No condition or condition is OK. Now we extract value for first column of extra chart.",5); }
  6828.             
  6829.              # Determine actual column value to use.
  6830.              my $rowkeyval;
  6831.             my $rowkeyok=0;
  6832.              foreach my $rowkeynum (0..@{$ExtraFirstColumnValuesType[$extranum]}-1) {
  6833.                  my $rowkeytype=$ExtraFirstColumnValuesType[$extranum][$rowkeynum];
  6834.                  my $rowkeytypeval=$ExtraFirstColumnValuesTypeVal[$extranum][$rowkeynum];
  6835.                 if ($rowkeytype eq 'URL') { 
  6836.                     if ($urlwithnoquery =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; }
  6837.                 } 
  6838.                  elsif ($rowkeytype eq 'QUERY_STRING') {
  6839.                     if ($Debug) { debug("  Extract value from '$standalonequery' with regex '$rowkeytypeval'.",5); }
  6840.                      if ($standalonequery =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; }
  6841.                  }
  6842.                  elsif ($rowkeytype eq 'REFERER') {
  6843.                      if ($field[$pos_referer] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; }
  6844.                  }
  6845.                  elsif ($rowkeytype eq 'UA') {
  6846.                      if ($field[$pos_agent] =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; }
  6847.                  }
  6848.                  elsif ($rowkeytype eq 'HOST') {
  6849.                      if ($HostResolved =~ /$rowkeytypeval/) { $rowkeyval = "$1"; $rowkeyok = 1; last; }
  6850.                  }
  6851.                  else { error("Wrong value of parameter ExtraSectionFirstColumnValues$extranum"); }
  6852.              }
  6853.             if (! $rowkeyok) { next; }    # End for this section
  6854.             if ($Debug) { debug("  Key val was found: $rowkeyval",5); }
  6855.  
  6856.              # Here we got all values to increase counters
  6857.              if ($PageBool && $ExtraStatTypes[$extranum] =~ /P/i) { ${'_section_' . $extranum . '_p'}{$rowkeyval}++; }
  6858.              ${'_section_' . $extranum . '_h'}{$rowkeyval}++;    # Must be set
  6859.              if ($ExtraStatTypes[$extranum] =~ /B/i) { ${'_section_' . $extranum . '_k'}{$rowkeyval}+=int($field[$pos_size]); }
  6860.              if ($ExtraStatTypes[$extranum] =~ /L/i) {
  6861.                  if (${'_section_' . $extranum . '_l'}{$rowkeyval}||0 < $timerecord) { ${'_section_' . $extranum . '_l'}{$rowkeyval}=$timerecord; }
  6862.              }
  6863.             # Check to avoid too large extra sections
  6864.             if (scalar keys %{'_section_' . $extranum . '_h'} > $ExtraTrackedRowsLimit) {
  6865.                 error(<<END_ERROR_TEXT);
  6866. The number of values found for extra section $extranum has grown too large.
  6867. In order prevent awstats from using an excessive amount of memory, the number
  6868. of values is currently limited to $ExtraTrackedRowsLimit. Perhaps you should consider
  6869. revising extract parameters for extra section $extranum. If you are certain you
  6870. want to track such a large data set, you can increase the limit by setting
  6871. ExtraTrackedRowsLimit in your awstats configuration file.
  6872. END_ERROR_TEXT
  6873.             }
  6874.          }
  6875.  
  6876.         # Every 20,000 approved lines after a flush, we test to clean too large hash arrays to flush data in tmp file
  6877.         if (++$counterforflushtest >= 20000) {
  6878.         #if (++$counterforflushtest >= 1) {
  6879.             if ((scalar keys %_host_u) > ($LIMITFLUSH<<2) || (scalar keys %_url_p) > $LIMITFLUSH) {
  6880.                 # warning("Warning: Try to run AWStats update process more frequently to analyze smaler log files.");
  6881.                 if ($^X =~ /activestate/i || $^X =~ /activeperl/i) {
  6882.                     # We don't flush if perl is activestate to avoid slowing process because of memory hole
  6883.                 }
  6884.                 else {
  6885.                     # Clean tmp hash arrays
  6886.                     #%TmpDNSLookup = ();
  6887.                     %TmpOS = %TmpRefererServer = %TmpRobot = %TmpBrowser = ();
  6888.                     # We flush if perl is not activestate
  6889.                     print "Flush history file on disk";
  6890.                     if ((scalar keys %_host_u) > ($LIMITFLUSH<<2)) { print " (unique hosts reach flush limit of ".($LIMITFLUSH<<2).")"; }
  6891.                     if ((scalar keys %_url_p) > $LIMITFLUSH) { print " (unique url reach flush limit of ".($LIMITFLUSH).")"; }
  6892.                     print "\n";
  6893.                     if ($Debug) {
  6894.                         debug("End of set of $counterforflushtest records: Some hash arrays are too large. We flush and clean some.",2);
  6895.                         print " _host_p:".(scalar keys %_host_p)." _host_h:".(scalar keys %_host_h)." _host_k:".(scalar keys %_host_k)." _host_l:".(scalar keys %_host_l)." _host_s:".(scalar keys %_host_s)." _host_u:".(scalar keys %_host_u)."\n";
  6896.                         print " _url_p:".(scalar keys %_url_p)." _url_k:".(scalar keys %_url_k)." _url_e:".(scalar keys %_url_e)." _url_x:".(scalar keys %_url_x)."\n";
  6897.                         print " _waithost_e:".(scalar keys %_waithost_e)." _waithost_l:".(scalar keys %_waithost_l)." _waithost_s:".(scalar keys %_waithost_s)." _waithost_u:".(scalar keys %_waithost_u)."\n";
  6898.                     }
  6899.                     &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($_));
  6900.                     &GetDelaySinceStart(1);    $NbOfLinesShowsteps=1;
  6901.                 }
  6902.             }
  6903.             $counterforflushtest=0;
  6904.         }
  6905.  
  6906.     }    # End of loop for processing new record.
  6907.  
  6908.     if ($Debug) {
  6909.         debug(" _host_p:".(scalar keys %_host_p)." _host_h:".(scalar keys %_host_h)." _host_k:".(scalar keys %_host_k)." _host_l:".(scalar keys %_host_l)." _host_s:".(scalar keys %_host_s)." _host_u:".(scalar keys %_host_u)."\n",1);
  6910.         debug(" _url_p:".(scalar keys %_url_p)." _url_k:".(scalar keys %_url_k)." _url_e:".(scalar keys %_url_e)." _url_x:".(scalar keys %_url_x)."\n",1);
  6911.         debug(" _waithost_e:".(scalar keys %_waithost_e)." _waithost_l:".(scalar keys %_waithost_l)." _waithost_s:".(scalar keys %_waithost_s)." _waithost_u:".(scalar keys %_waithost_u)."\n",1);
  6912.         debug("End of processing log file (AWStats memory cache is TmpDNSLookup=".(scalar keys %TmpDNSLookup)." TmpBrowser=".(scalar keys %TmpBrowser)." TmpOS=".(scalar keys %TmpOS)." TmpRefererServer=".(scalar keys %TmpRefererServer)." TmpRobot=".(scalar keys %TmpRobot).")",1);
  6913.     }
  6914.  
  6915.     # Save current processed month $lastprocessedmonth
  6916.     # If lastprocessedmonth > 0 means there is at least one approved new record in log or at least one existing history file
  6917.     if ($lastprocessedmonth) {    # TODO: Do not save if we are sure a flush was just already done
  6918.         # Get last line
  6919.         seek(LOG,$lastlineoffset,0);
  6920.         my $line=<LOG>;
  6921.          chomp $line; $line =~ s/\r$//;
  6922.         if (! $NbOfLinesParsed) {
  6923.             # TODO If there was no lines parsed (log was empty), we only update LastUpdate line with YYYYMMDDHHMMSS 0 0 0 0 0
  6924.             &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line));
  6925.         }
  6926.         else {
  6927.             &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,1,1,"all",($lastlinenb+$NbOfLinesParsed),$lastlineoffset,&CheckSum($line));
  6928.         }
  6929.     }
  6930.  
  6931.     if ($Debug) { debug("Close log file \"$LogFile\""); }
  6932.     close LOG || error("Command for pipe '$LogFile' failed");
  6933.  
  6934.     # Process the Rename - Archive - Purge phase
  6935.     my $renameok=1; my $archiveok=1;
  6936.  
  6937.     # Open Log file for writing if PurgeLogFile is on
  6938.     if ($PurgeLogFile == 1) {
  6939.         if ($ArchiveLogRecords == 1) {
  6940.             $ArchiveFileName="$DirData/${PROG}_archive$FileSuffix.log";
  6941.             open(LOG,"+<$LogFile") || error("Enable to archive log records of \"$LogFile\" into \"$ArchiveFileName\" because source can't be opened for read and write: $!<br />\n");
  6942.         }
  6943.         else {
  6944.             open(LOG,"+<$LogFile");
  6945.         }
  6946.         binmode LOG;
  6947.     }
  6948.  
  6949.     # Rename all HISTORYTMP files into HISTORYTXT
  6950.     &Rename_All_Tmp_History;
  6951.  
  6952.     # Purge Log file if option is on and all renaming are ok
  6953.     if ($PurgeLogFile == 1) {
  6954.         # Archive LOG file into ARCHIVELOG
  6955.         if ($ArchiveLogRecords == 1) {
  6956.             if ($Debug) { debug("Start of archiving log file"); }
  6957.             open(ARCHIVELOG,">>$ArchiveFileName") || error("Couldn't open file \"$ArchiveFileName\" to archive log: $!");
  6958.             binmode ARCHIVELOG;
  6959.             while (<LOG>) {
  6960.                 if (! print ARCHIVELOG $_) { $archiveok=0; last; }
  6961.             }
  6962.             close(ARCHIVELOG) || error("Archiving failed during closing archive: $!");
  6963.             if ($SaveDatabaseFilesWithPermissionsForEveryone) {    chmod 0666,"$ArchiveFileName"; }
  6964.             if ($Debug) { debug("End of archiving log file"); }
  6965.         }
  6966.         # If rename and archive ok
  6967.         if ($renameok && $archiveok) {
  6968.             if ($Debug) { debug("Purge log file"); }
  6969.             my $bold=($ENV{'GATEWAY_INTERFACE'}?'<b>':'');
  6970.             my $unbold=($ENV{'GATEWAY_INTERFACE'}?'</b>':'');
  6971.             my $br=($ENV{'GATEWAY_INTERFACE'}?'<br />':'');
  6972.             truncate(LOG,0) || warning("Warning: $bold$PROG$unbold couldn't purge logfile \"$bold$LogFile$unbold\".$br\nChange your logfile permissions to allow write for your web server CGI process or change PurgeLogFile=1 into PurgeLogFile=0 in configure file and think to purge sometines manually your logfile (just after running an update process to not loose any not already processed records your log file contains).");
  6973.         }
  6974.         close(LOG);
  6975.     }
  6976.  
  6977.     if ($DNSLookup==1 && $DNSLookupAlreadyDone) {
  6978.         # DNSLookup warning
  6979.         my $bold=($ENV{'GATEWAY_INTERFACE'}?'<b>':'');
  6980.         my $unbold=($ENV{'GATEWAY_INTERFACE'}?'</b>':'');
  6981.         my $br=($ENV{'GATEWAY_INTERFACE'}?'<br />':'');
  6982.         warning("Warning: $bold$PROG$unbold has detected that some hosts names were already resolved in your logfile $bold$DNSLookupAlreadyDone$unbold.$br\nIf DNS lookup was already made by the logger (web server), you should change your setup DNSLookup=$DNSLookup into DNSLookup=0 to increase $PROG speed.");
  6983.     }
  6984.     if ($DNSLookup==1 && $NbOfNewLines) {
  6985.         # Save new DNS last update cache file
  6986.         Save_DNS_Cache_File(\%TmpDNSLookup,"$DirData/$DNSLastUpdateCacheFile","$FileSuffix");    # Save into file using FileSuffix
  6987.     }
  6988.  
  6989.     if ($EnableLockForUpdate) {
  6990.         # Remove lock
  6991.         &Lock_Update(0);
  6992.         # Restore signals handler
  6993.         $SIG{INT} = 'DEFAULT';    # 2
  6994.         #$SIG{KILL} = 'DEFAULT';    # 9
  6995.         #$SIG{TERM} = 'DEFAULT';    # 15
  6996.     }
  6997.  
  6998. }
  6999. # End of log processing if ($UPdateStats)
  7000.  
  7001.  
  7002. #---------------------------------------------------------------------
  7003. # SHOW REPORT
  7004. #---------------------------------------------------------------------
  7005.  
  7006. if (scalar keys %HTMLOutput) {
  7007.  
  7008.     my $max_p; my $max_h; my $max_k; my $max_v;
  7009.     my $total_u; my $total_v; my $total_p; my $total_h; my $total_k; my $total_e; my $total_x; my $total_s; my $total_l; my $total_r;
  7010.     my $average_u; my $average_v; my $average_p; my $average_h; my $average_k; my $average_s;
  7011.     my $rest_p; my $rest_h; my $rest_k; my $rest_e; my $rest_x; my $rest_s; my $rest_l; my $rest_r;
  7012.     my $average_nb;
  7013.  
  7014.     # Define the NewLinkParams for main chart
  7015.     my $NewLinkParams=${QueryString};
  7016.     $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  7017.     $NewLinkParams =~ s/(^|&)output(=\w*|$)//i;
  7018.     $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  7019.     $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  7020.     my $NewLinkTarget='';
  7021.     if ($DetailedReportsOnNewWindows) { $NewLinkTarget=" target=\"awstatsbis\""; }
  7022.     if (($FrameName eq 'mainleft' || $FrameName eq 'mainright') && $DetailedReportsOnNewWindows < 2) {
  7023.         $NewLinkParams.="&framename=mainright";
  7024.         $NewLinkTarget=" target=\"mainright\"";
  7025.     }
  7026.     $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  7027.     if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  7028.  
  7029.     if ($FrameName ne 'mainleft') {
  7030.  
  7031.         # READING DATA
  7032.         #-------------
  7033.         &Init_HashArray();
  7034.  
  7035.         # Loop on each month of year
  7036.         for (my $ix=12; $ix>=1; $ix--) {
  7037.             my $monthix=sprintf("%02s",$ix);
  7038.             if ($MonthRequired eq 'all' || $monthix eq $MonthRequired) {
  7039.                 &Read_History_With_TmpUpdate($YearRequired,$monthix,0,0,"all");                # Read full history file
  7040.             }
  7041.             elsif (($HTMLOutput{'main'} && $ShowMonthStats) || $HTMLOutput{'alldays'}) {
  7042.                 &Read_History_With_TmpUpdate($YearRequired,$monthix,0,0,"general time");    # Read general and time sections.
  7043.             }
  7044.         }
  7045.     }
  7046.  
  7047.     # HTMLHeadSection
  7048.     if ($FrameName ne 'index' && $FrameName ne 'mainleft') {
  7049.         print "<a name=\"top\"> </a>\n\n";
  7050.         print "$HTMLHeadSection\n";
  7051.         print "\n";
  7052.     }
  7053.  
  7054.     # Call to plugins' function AddHTMLBodyHeader
  7055.     foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLBodyHeader'}})  {
  7056.         my $function="AddHTMLBodyHeader_$pluginname()";
  7057.         eval("$function");
  7058.     }
  7059.  
  7060.     # TOP BAN
  7061.     #---------------------------------------------------------------------
  7062.     if ($ShowMenu || $FrameName eq 'mainleft') {
  7063.         my $frame=($FrameName eq 'mainleft');
  7064.         my $WIDTHMENU1=($FrameName eq 'mainleft'?$FRAMEWIDTH:150);
  7065.  
  7066.         if ($Debug) { debug("ShowTopBan",2); }
  7067.         print "$Center<a name=\"menu\"> </a>\n";
  7068.  
  7069.         
  7070.         if ($FrameName ne 'mainleft') {
  7071.             my $NewLinkParams=${QueryString};
  7072.             $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  7073.             $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  7074.             $NewLinkParams =~ s/(^|&)year=[^&]*//i;
  7075.             $NewLinkParams =~ s/(^|&)month=[^&]*//i;
  7076.             $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  7077.             $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  7078.             my $NewLinkTarget='';
  7079.             if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; }
  7080.             print "<form name=\"FormDateFilter\" action=\"".XMLEncode("$AWScript?${NewLinkParams}")."\" style=\"padding: 0px 0px 0px 0px; margin-top: 0\"$NewLinkTarget>\n";
  7081.         }
  7082.  
  7083.         if ($QueryString !~ /buildpdf/i) {
  7084.             print "<table class=\"aws_border\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\" width=\"100%\">\n";
  7085.             print "<tr><td>\n";
  7086.             print "<table class=\"aws_data\" border=\"0\" cellpadding=\"1\" cellspacing=\"0\" width=\"100%\">\n";
  7087.         }
  7088.         else {
  7089.             print "<table width=\"100%\">\n";    
  7090.         }
  7091.  
  7092.         if ($FrameName ne 'mainright') {
  7093.             # Print Statistics Of
  7094.             if ($FrameName eq 'mainleft') { print "<tr><td class=\"awsm\"><b>$Message[7]:</b></td></tr><tr><td class=\"aws\"><span style=\"font-size: 12px;\">$SiteDomain</span></td>"; }
  7095.             else { print "<tr><td class=\"aws\" valign=\"middle\"><b>$Message[7]:</b> </td><td class=\"aws\" valign=\"middle\"><span style=\"font-size: 14px;\">$SiteDomain</span></td>"; }
  7096.  
  7097.             # Logo and flags
  7098.             if ($FrameName ne 'mainleft') {
  7099.                 if ($LogoLink =~ "http://awstats.sourceforge.net") {
  7100.                     print "<td align=\"right\" rowspan=\"3\"><a href=\"".XMLEncode($LogoLink)."\" target=\"awstatshome\"><img src=\"$DirIcons/other/$Logo\" border=\"0\"".AltTitle(ucfirst($PROG)." Web Site")." /></a>";
  7101.                 }
  7102.                 else {
  7103.                     print "<td align=\"right\" rowspan=\"3\"><a href=\"".XMLEncode($LogoLink)."\" target=\"awstatshome\"><img src=\"$DirIcons/other/$Logo\" border=\"0\" /></a>";
  7104.                 }
  7105.                 if (! $StaticLinks) { print "<br />"; Show_Flag_Links($Lang); }
  7106.                 print "</td>";
  7107.             }
  7108.             print  "</tr>\n";
  7109.         }
  7110.         if ($FrameName ne 'mainleft') {
  7111.             # Print Last Update
  7112.             print "<tr valign=\"middle\"><td class=\"aws\" valign=\"middle\" width=\"$WIDTHMENU1\"><b>$Message[35]:</b> </td>";
  7113.             print "<td class=\"aws\" valign=\"middle\"><span style=\"font-size: 12px;\">";
  7114.             if ($LastUpdate) { print Format_Date($LastUpdate,0); }
  7115.             else {
  7116.                 # Here NbOfOldLines = 0 (because LastUpdate is not defined)
  7117.                 if (! $UpdateStats) { print "<span style=\"color: #880000\">$Message[24]</span>"; }
  7118.                 else { print "<span style=\"color: #880000\">No qualified records found in log ($NbOfLinesCorrupted corrupted, $NbOfLinesDropped dropped)</span>"; }
  7119.                 
  7120.             }
  7121.             print "</span>";
  7122.             # Print Update Now link
  7123.             if ($AllowToUpdateStatsFromBrowser && ! $StaticLinks) {
  7124.                 my $NewLinkParams=${QueryString};
  7125.                 $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  7126.                 $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  7127.                 $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  7128.                 if ($FrameName eq 'mainright') { $NewLinkParams.="&framename=mainright"; }
  7129.                 $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  7130.                 if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  7131.                 print "       ";
  7132.                 print "<a href=\"".XMLEncode("$AWScript?${NewLinkParams}update=1")."\">$Message[74]</a>";
  7133.             }
  7134.             print "</td>";
  7135.  
  7136.             # Logo and flags
  7137.             if ($FrameName eq 'mainright') {
  7138.                 if ($LogoLink =~ "http://awstats.sourceforge.net") {
  7139.                     print "<td align=\"right\" rowspan=\"2\"><a href=\"".XMLEncode($LogoLink)."\" target=\"awstatshome\"><img src=\"$DirIcons/other/$Logo\" border=\"0\"".AltTitle(ucfirst($PROG)." Web Site")." /></a>\n";
  7140.                 }
  7141.                 else {
  7142.                     print "<td align=\"right\" rowspan=\"2\"><a href=\"".XMLEncode($LogoLink)."\" target=\"awstatshome\"><img src=\"$DirIcons/other/$Logo\" border=\"0\" /></a>\n";
  7143.                 }
  7144.                 if (! $StaticLinks) { print "<br />"; Show_Flag_Links($Lang); }
  7145.                 print "</td>";
  7146.             }
  7147.  
  7148.             print "</tr>\n";
  7149.             # Print selected period of analysis (month and year required)
  7150.             print "<tr><td class=\"aws\" valign=\"middle\"><b>$Message[133]:</b></td>";
  7151.             print "<td class=\"aws\" valign=\"middle\">";
  7152.             if ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) {
  7153.                 print "<select class=\"aws_formfield\" name=\"month\">\n";
  7154.                 foreach (1..12) { my $monthix=sprintf("%02s",$_); print "<option".($MonthRequired eq "$monthix"?" selected=\"true\"":"")." value=\"$monthix\">$MonthNumLib{$monthix}</option>\n"; }
  7155.                 if ($AllowFullYearView >= 2) {
  7156.                     print "<option".($MonthRequired eq 'all'?" selected=\"true\"":"")." value=\"all\">- $Message[6] -</option>\n";
  7157.                 }
  7158.                 print "</select>\n";
  7159.                 print "<select class=\"aws_formfield\" name=\"year\">\n";
  7160.                 # Add YearRequired in list if not in ListOfYears
  7161.                 $ListOfYears{$YearRequired}||=$MonthRequired;
  7162.                 foreach (sort keys %ListOfYears) { print "<option".($YearRequired eq "$_"?" selected=\"true\"":"")." value=\"$_\">$_</option>\n"; }
  7163.                 print "</select>\n";
  7164.                 print "<input type=\"hidden\" name=\"output\" value=\"".join(',',keys %HTMLOutput)."\" />\n";
  7165.                 if ($SiteConfig) { print "<input type=\"hidden\" name=\"config\" value=\"$SiteConfig\" />\n"; }
  7166.                  if ($DirConfig)  { print "<input type=\"hidden\" name=\"configdir\" value=\"$DirConfig\" />\n"; }
  7167.                 if ($QueryString =~ /lang=(\w+)/i) { print "<input type=\"hidden\" name=\"lang\" value=\"$1\" />\n"; }
  7168.                 if ($QueryString =~ /debug=(\d+)/i) { print "<input type=\"hidden\" name=\"debug\" value=\"$1\" />\n"; }
  7169.                 if ($FrameName eq 'mainright') { print "<input type=\"hidden\" name=\"framename\" value=\"index\" />\n"; }
  7170.                 print "<input type=\"submit\" value=\" $Message[115] \" class=\"aws_button\" />";
  7171.             }
  7172.             else {
  7173.                 print "<span style=\"font-size: 14px;\">";
  7174.                 if ($MonthRequired eq 'all') { print "$Message[6] $YearRequired"; }
  7175.                 else { print "$Message[5] $MonthNumLib{$MonthRequired} $YearRequired"; }
  7176.                 print "</span>";
  7177.             }
  7178.             print "</td></tr>\n";
  7179.         }
  7180.         if ($QueryString !~ /buidpdf/i) {
  7181.             print "</table>\n";
  7182.             print "</td></tr></table>\n";
  7183.         }
  7184.         else {
  7185.             print "</table>\n";
  7186.         }
  7187.  
  7188.         if ($FrameName ne 'mainleft') {    print "</form>\n"; }
  7189.         else { print "<br />\n"; }
  7190.         print "\n";
  7191.     }
  7192.     
  7193.     # Call to plugins' function AddHTMLMenuHeader
  7194.     foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLMenuHeader'}})  {
  7195.         my $function="AddHTMLMenuHeader_$pluginname()";
  7196.         eval("$function");
  7197.     }
  7198.  
  7199.     # MENU
  7200.     #---------------------------------------------------------------------
  7201.     if ($ShowMenu || $FrameName eq 'mainleft') {
  7202.         my $frame=($FrameName eq 'mainleft');
  7203.         my $WIDTHMENU1=($FrameName eq 'mainleft'?$FRAMEWIDTH:150);
  7204.  
  7205.         if ($Debug) { debug("ShowMenu",2); }
  7206.  
  7207.         # Print menu links
  7208.         if (($HTMLOutput{'main'} && $FrameName ne 'mainright') || $FrameName eq 'mainleft') {    # If main page asked
  7209.             # Define link anchor            
  7210.             my $linkanchor=($FrameName eq 'mainleft'?"$AWScript?${NewLinkParams}":"");
  7211.             if ($linkanchor && ($linkanchor !~ /framename=mainright/)) { $linkanchor.="framename=mainright"; }
  7212.             $linkanchor =~ s/&$//; $linkanchor=XMLEncode("$linkanchor");
  7213.             # Define target
  7214.             my $targetpage=($FrameName eq 'mainleft'?" target=\"mainright\"":"");
  7215.             # Print Menu
  7216.             my $linetitle;
  7217.             if (! $PluginsLoaded{'ShowMenu'}{'menuapplet'}) {
  7218.                 my $menuicon=0;
  7219.                 # Menu HTML
  7220.                 print "<table".($frame?" cellspacing=\"0\" cellpadding=\"0\" border=\"0\"":"").">\n";
  7221.                 if ($FrameName eq 'mainleft' && $ShowMonthStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#TOP\"$targetpage>$Message[128]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7222.                 # When
  7223.                 $linetitle=&AtLeastOneNotNull($ShowMonthStats,$ShowDaysOfMonthStats,$ShowDaysOfWeekStats,$ShowHoursStats);
  7224.                 if ($linetitle) { print "<tr><td class=\"awsm\" width=\"$WIDTHMENU1\"".($frame?"":" valign=\"top\"").">".($menuicon?"<img src=\"$DirIcons/other/menu4.png\" /> ":"")."<b>$Message[93]:</b></td>\n"; }
  7225.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7226.                 if ($ShowMonthStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#month\"$targetpage>$Message[162]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7227.                 #if ($ShowMonthDayStats)     { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=alldays"):"$PROG$StaticLinks.alldays.$StaticExt")."\"$NewLinkTarget>$Message[130]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7228.                 if ($ShowDaysOfMonthStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#daysofmonth\"$targetpage>$Message[138]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7229.                 if ($ShowDaysOfWeekStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#daysofweek\"$targetpage>$Message[91]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7230.                 if ($ShowHoursStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#hours\"$targetpage>$Message[20]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7231.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7232.                 # Who
  7233.                 $linetitle=&AtLeastOneNotNull($ShowDomainsStats,$ShowHostsStats,$ShowAuthenticatedUsers,$ShowEMailSenders,$ShowEMailReceivers,$ShowRobotsStats,$ShowWormsStats);
  7234.                 if ($linetitle) { print "<tr><td class=\"awsm\"".($frame?"":" valign=\"top\"").">".($menuicon?"<img src=\"$DirIcons/other/menu5.png\" /> ":"")."<b>$Message[92]:</b></td>\n"; }
  7235.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7236.                 if ($ShowDomainsStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#countries\"$targetpage>$Message[148]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7237.                 if ($ShowDomainsStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=alldomains"):"$PROG$StaticLinks.alldomains.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7238.                 if ($ShowHostsStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#visitors\"$targetpage>".ucfirst($Message[81])."</a>"; print ($frame?"</td></tr>\n":"   "); }
  7239.                 if ($ShowHostsStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allhosts"):"$PROG$StaticLinks.allhosts.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7240.                 if ($ShowHostsStats =~ /L/i) { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lasthosts"):"$PROG$StaticLinks.lasthosts.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7241.                 if ($ShowHostsStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownip"):"$PROG$StaticLinks.unknownip.$StaticExt")."\"$NewLinkTarget>$Message[45]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7242.                 if ($ShowAuthenticatedUsers) { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#logins\"$targetpage>$Message[94]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7243.                 if ($ShowAuthenticatedUsers) { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=alllogins"):"$PROG$StaticLinks.alllogins.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7244.                 if ($ShowAuthenticatedUsers =~ /L/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastlogins"):"$PROG$StaticLinks.lastlogins.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7245.                 if ($ShowEMailSenders)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#emailsenders\"$targetpage>$Message[131]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7246.                 if ($ShowEMailSenders)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allemails"):"$PROG$StaticLinks.allemails.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7247.                 if ($ShowEMailSenders =~ /L/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastemails"):"$PROG$StaticLinks.lastemails.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7248.                 if ($ShowEMailReceivers)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#emailreceivers\"$targetpage>$Message[132]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7249.                 if ($ShowEMailReceivers)     { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allemailr"):"$PROG$StaticLinks.allemailr.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7250.                 if ($ShowEMailReceivers =~ /L/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastemailr"):"$PROG$StaticLinks.lastemailr.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7251.                 if ($ShowRobotsStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#robots\"$targetpage>$Message[53]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7252.                 if ($ShowRobotsStats)          { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allrobots"):"$PROG$StaticLinks.allrobots.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7253.                 if ($ShowRobotsStats =~ /L/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastrobots"):"$PROG$StaticLinks.lastrobots.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7254.                 if ($ShowWormsStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#worms\"$targetpage>$Message[136]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7255.                 #if ($ShowWormsStats)          { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allworms"):"$PROG$StaticLinks.allworms.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7256.                 #if ($ShowWormsStats =~ /L/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastworms"):"$PROG$StaticLinks.lastworms.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7257.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7258.                 # Navigation
  7259.                 $linetitle=&AtLeastOneNotNull($ShowSessionsStats,$ShowPagesStats,$ShowFileTypesStats,$ShowFileSizesStats,$ShowOSStats,$ShowBrowsersStats,$ShowScreenSizeStats);
  7260.                 if ($linetitle) { print "<tr><td class=\"awsm\"".($frame?"":" valign=\"top\"").">".($menuicon?"<img src=\"$DirIcons/other/menu2.png\" /> ":"")."<b>$Message[72]:</b></td>\n"; }
  7261.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7262.                 if ($ShowSessionsStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#sessions\"$targetpage>$Message[117]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7263.                 if ($ShowFileTypesStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#filetypes\"$targetpage>$Message[73]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7264.                 if ($ShowPagesStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#urls\"$targetpage>$Message[29]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7265.                 if ($ShowPagesStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urldetail"):"$PROG$StaticLinks.urldetail.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7266.                 if ($ShowPagesStats =~ /E/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urlentry"):"$PROG$StaticLinks.urlentry.$StaticExt")."\"$NewLinkTarget>$Message[104]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7267.                 if ($ShowPagesStats =~ /X/i)    { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urlexit"):"$PROG$StaticLinks.urlexit.$StaticExt")."\"$NewLinkTarget>$Message[116]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7268.                 if ($ShowOSStats)             { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#os\"$targetpage>$Message[59]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7269.                 if ($ShowOSStats)              { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=osdetail"):"$PROG$StaticLinks.osdetail.$StaticExt")."\"$NewLinkTarget>$Message[58]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7270.                 if ($ShowOSStats)             { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownos"):"$PROG$StaticLinks.unknownos.$StaticExt")."\"$NewLinkTarget>$Message[0]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7271.                 if ($ShowBrowsersStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#browsers\"$targetpage>$Message[21]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7272.                 if ($ShowBrowsersStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=browserdetail"):"$PROG$StaticLinks.browserdetail.$StaticExt")."\"$NewLinkTarget>$Message[58]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7273.                 if ($ShowBrowsersStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownbrowser"):"$PROG$StaticLinks.unknownbrowser.$StaticExt")."\"$NewLinkTarget>$Message[0]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7274.                 if ($ShowScreenSizeStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#screensizes\"$targetpage>$Message[135]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7275.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7276.                 # Referers
  7277.                 $linetitle=&AtLeastOneNotNull($ShowOriginStats,$ShowKeyphrasesStats,$ShowKeywordsStats);
  7278.                 if ($linetitle) { print "<tr><td class=\"awsm\"".($frame?"":" valign=\"top\"").">".($menuicon?"<img src=\"$DirIcons/other/menu7.png\" /> ":"")."<b>$Message[23]:</b></td>\n"; }
  7279.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7280.                 if ($ShowOriginStats)         { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#referer\"$targetpage>$Message[37]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7281.                 if ($ShowOriginStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=refererse"):"$PROG$StaticLinks.refererse.$StaticExt")."\"$NewLinkTarget>$Message[126]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7282.                 if ($ShowOriginStats)         { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=refererpages"):"$PROG$StaticLinks.refererpages.$StaticExt")."\"$NewLinkTarget>$Message[127]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7283.                 if ($ShowKeyphrasesStats || $ShowKeywordsStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#keys\"$targetpage>$Message[14]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7284.                 if ($ShowKeyphrasesStats)     { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=keyphrases"):"$PROG$StaticLinks.keyphrases.$StaticExt")."\"$NewLinkTarget>$Message[120]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7285.                 if ($ShowKeywordsStats)          { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=keywords"):"$PROG$StaticLinks.keywords.$StaticExt")."\"$NewLinkTarget>$Message[121]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7286.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7287.                 # Others
  7288.                 $linetitle=&AtLeastOneNotNull($ShowFileTypesStats=~/C/i,$ShowMiscStats,$ShowHTTPErrorsStats,$ShowSMTPErrorsStats,$ShowClusterStats);
  7289.                 if ($linetitle) { print "<tr><td class=\"awsm\"".($frame?"":" valign=\"top\"").">".($menuicon?"<img src=\"$DirIcons/other/menu8.png\" /> ":"")."<b>$Message[2]:</b></td>\n"; }
  7290.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7291.                 if ($ShowFileTypesStats =~ /C/i)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#filetypes\"$targetpage>$Message[98]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7292.                 if ($ShowMiscStats)              { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#misc\"$targetpage>$Message[139]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7293.                 if ($ShowHTTPErrorsStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#errors\"$targetpage>$Message[32]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7294.                 foreach (keys %TrapInfosForHTTPErrorCodes) {
  7295.                     if ($ShowHTTPErrorsStats)     { print ($frame?"<tr><td class=\"awsm\">   <img height=\"8\" width=\"9\" src=\"$DirIcons/other/page.png\" alt=\"...\" /> ":""); print "<a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=errors$_"):"$PROG$StaticLinks.errors$_.$StaticExt")."\"$NewLinkTarget>$Message[31]</a>\n"; print ($frame?"</td></tr>\n":"   "); }
  7296.                 }
  7297.                 if ($ShowSMTPErrorsStats)     { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#errors\"$targetpage>$Message[147]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7298.                 if ($ShowClusterStats)          { print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#clusters\"$targetpage>$Message[155]</a>"; print ($frame?"</td></tr>\n":"   "); }
  7299.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7300.                 # Extra/Marketing
  7301.                  $linetitle=&AtLeastOneNotNull(@ExtraStatTypes);
  7302.                 if ($linetitle) { print "<tr><td class=\"awsm\"".($frame?"":" valign=\"top\"")."><b>$Message[134]:</b></td>\n"; }
  7303.                 if ($linetitle) { print ($frame?"</tr>\n":"<td class=\"awsm\">"); }
  7304.                 foreach (1..@ExtraName-1) {
  7305.                     print ($frame?"<tr><td class=\"awsm\">":""); print "<a href=\"$linkanchor#extra$_\"$targetpage>$ExtraName[$_]</a>\n"; print ($frame?"</td></tr>\n":"   ");
  7306.                 }
  7307.                 if ($linetitle) { print ($frame?"":"</td></tr>\n"); }
  7308.                 print "</table>\n";
  7309.             }
  7310.             else {
  7311.                 # Menu Applet
  7312.                 if ($frame) { }
  7313.                 else {}
  7314.             }
  7315.             #print ($frame?"":"<br />\n");
  7316.             print "<br />\n";
  7317.         }
  7318.         # Print Back link
  7319.         elsif (! $HTMLOutput{'main'}) {
  7320.             print "<table>\n";
  7321.             $NewLinkParams =~ s/(^|&)hostfilter=[^&]*//i;
  7322.             $NewLinkParams =~ s/(^|&)urlfilter=[^&]*//i;
  7323.             $NewLinkParams =~ s/(^|&)refererpagesfilter=[^&]*//i;
  7324.             $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/&$//;
  7325.             if (! $DetailedReportsOnNewWindows || $FrameName eq 'mainright' || $QueryString =~ /buildpdf/i) {
  7326.                 print "<tr><td class=\"aws\"><a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript".(${NewLinkParams}?"?${NewLinkParams}":"")):"$PROG$StaticLinks.$StaticExt")."\">$Message[76]</a></td></tr>\n";
  7327.             }
  7328.             else {
  7329.                 print "<tr><td class=\"aws\"><a href=\"javascript:parent.window.close();\">$Message[118]</a></td></tr>\n";
  7330.             }
  7331.             print "</table>\n";
  7332.             print "\n";
  7333.         }
  7334.     }
  7335.  
  7336.     # Call to plugins' function AddHTMLMenuFooter
  7337.     foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLMenuFooter'}})  {
  7338.         my $function="AddHTMLMenuFooter_$pluginname()";
  7339.         eval("$function");
  7340.     }
  7341.  
  7342.     # Exit if left frame
  7343.     if ($FrameName eq 'mainleft') {
  7344.         &html_end(0);
  7345.         exit 0;
  7346.     }
  7347.  
  7348.     # FirstTime LastTime TotalVisits TotalUnique TotalPages TotalHits TotalBytes TotalHostsKnown TotalHostsUnknown
  7349.     my $FirstTime=0;
  7350.     my $LastTime=0;
  7351.     $TotalUnique=$TotalVisits=$TotalPages=$TotalHits=$TotalBytes=0;
  7352.     $TotalNotViewedPages=$TotalNotViewedHits=$TotalNotViewedBytes=0;
  7353.     $TotalHostsKnown=$TotalHostsUnknown=0;
  7354.     my $beginmonth=$MonthRequired;my $endmonth=$MonthRequired;
  7355.     if ($MonthRequired eq 'all') { $beginmonth=1;$endmonth=12; }
  7356.     for (my $month=$beginmonth; $month<=$endmonth; $month++) {
  7357.         my $monthix=sprintf("%02s",$month);
  7358.         if ($FirstTime{$YearRequired.$monthix} && ($FirstTime == 0 || $FirstTime > $FirstTime{$YearRequired.$monthix})) { $FirstTime = $FirstTime{$YearRequired.$monthix}; }
  7359.         if ($LastTime < ($LastTime{$YearRequired.$monthix}||0)) { $LastTime = $LastTime{$YearRequired.$monthix}; }
  7360.         $TotalHostsKnown+=$MonthHostsKnown{$YearRequired.$monthix}||0;        # Wrong in year view
  7361.         $TotalHostsUnknown+=$MonthHostsUnknown{$YearRequired.$monthix}||0;    # Wrong in year view
  7362.         $TotalUnique+=$MonthUnique{$YearRequired.$monthix}||0;                # Wrong in year view
  7363.         $TotalVisits+=$MonthVisits{$YearRequired.$monthix}||0;
  7364.         $TotalPages+=$MonthPages{$YearRequired.$monthix}||0;
  7365.         $TotalHits+=$MonthHits{$YearRequired.$monthix}||0;
  7366.         $TotalBytes+=$MonthBytes{$YearRequired.$monthix}||0;
  7367.         $TotalNotViewedPages+=$MonthNotViewedPages{$YearRequired.$monthix}||0;
  7368.         $TotalNotViewedHits+=$MonthNotViewedHits{$YearRequired.$monthix}||0;
  7369.         $TotalNotViewedBytes+=$MonthNotViewedBytes{$YearRequired.$monthix}||0;
  7370.     }
  7371.     # TotalHitsErrors TotalBytesErrors
  7372.     my $TotalHitsErrors=0; my $TotalBytesErrors=0;
  7373.     foreach (keys %_errors_h) { $TotalHitsErrors+=$_errors_h{$_}; $TotalBytesErrors+=$_errors_k{$_}; }
  7374.     # TotalEntries (if not already specifically counted, we init it from _url_e hash table)
  7375.     if (!$TotalEntries) { foreach (keys %_url_e) { $TotalEntries+=$_url_e{$_}; } }
  7376.     # TotalExits (if not already specifically counted, we init it from _url_x hash table)
  7377.     if (!$TotalExits) { foreach (keys %_url_x) { $TotalExits+=$_url_x{$_}; } }
  7378.     # TotalBytesPages (if not already specifically counted, we init it from _url_k hash table)
  7379.     if (!$TotalBytesPages) { foreach (keys %_url_k) { $TotalBytesPages+=$_url_k{$_}; } }
  7380.     # TotalKeyphrases (if not already specifically counted, we init it from _keyphrases hash table)
  7381.     if (!$TotalKeyphrases) { foreach (keys %_keyphrases) { $TotalKeyphrases+=$_keyphrases{$_}; } }
  7382.     # TotalKeywords (if not already specifically counted, we init it from _keywords hash table)
  7383.     if (!$TotalKeywords) { foreach (keys %_keywords) { $TotalKeywords+=$_keywords{$_}; } }
  7384.     # TotalSearchEnginesPages (if not already specifically counted, we init it from _se_referrals_p hash table)
  7385.     if (!$TotalSearchEnginesPages) { foreach (keys %_se_referrals_p) { $TotalSearchEnginesPages+=$_se_referrals_p{$_}; } }
  7386.     # TotalSearchEnginesHits (if not already specifically counted, we init it from _se_referrals_h hash table)
  7387.     if (!$TotalSearchEnginesHits) { foreach (keys %_se_referrals_h) { $TotalSearchEnginesHits+=$_se_referrals_h{$_}; } }
  7388.     # TotalRefererPages (if not already specifically counted, we init it from _pagesrefs_p hash table)
  7389.     if (!$TotalRefererPages) { foreach (keys %_pagesrefs_p) { $TotalRefererPages+=$_pagesrefs_p{$_}; } }
  7390.     # TotalRefererHits (if not already specifically counted, we init it from _pagesrefs_h hash table)
  7391.     if (!$TotalRefererHits) { foreach (keys %_pagesrefs_h) { $TotalRefererHits+=$_pagesrefs_h{$_}; } }
  7392.     # TotalDifferentPages (if not already specifically counted, we init it from _url_p hash table)
  7393.     $TotalDifferentPages||=scalar keys %_url_p;
  7394.     # TotalDifferentKeyphrases (if not already specifically counted, we init it from _keyphrases hash table)
  7395.     $TotalDifferentKeyphrases||=scalar keys %_keyphrases;
  7396.     # TotalDifferentKeywords (if not already specifically counted, we init it from _keywords hash table)
  7397.     $TotalDifferentKeywords||=scalar keys %_keywords;
  7398.     # TotalDifferentSearchEngines (if not already specifically counted, we init it from _se_referrals_h hash table)
  7399.     $TotalDifferentSearchEngines||=scalar keys %_se_referrals_h;
  7400.     # TotalDifferentReferer (if not already specifically counted, we init it from _pagesrefs_h hash table)
  7401.     $TotalDifferentReferer||=scalar keys %_pagesrefs_h;
  7402.  
  7403.     # Define firstdaytocountaverage, lastdaytocountaverage, firstdaytoshowtime, lastdaytoshowtime
  7404.     my $firstdaytocountaverage=$nowyear.$nowmonth."01";                # Set day cursor to 1st day of month
  7405.     my $firstdaytoshowtime=$nowyear.$nowmonth."01";                    # Set day cursor to 1st day of month
  7406.     my $lastdaytocountaverage=$nowyear.$nowmonth.$nowday;            # Set day cursor to today
  7407.     my $lastdaytoshowtime=$nowyear.$nowmonth."31";                    # Set day cursor to last day of month
  7408.     if ($MonthRequired eq 'all') {
  7409.         $firstdaytocountaverage=$YearRequired."0101";                # Set day cursor to 1st day of the required year
  7410.     }
  7411.     if (($MonthRequired ne $nowmonth && $MonthRequired ne 'all') || $YearRequired ne $nowyear) {
  7412.         if ($MonthRequired eq 'all') {
  7413.             $firstdaytocountaverage=$YearRequired."0101";            # Set day cursor to 1st day of the required year
  7414.             $firstdaytoshowtime=$YearRequired."1201";                # Set day cursor to 1st day of last month of required year
  7415.             $lastdaytocountaverage=$YearRequired."1231";            # Set day cursor to last day of the required year
  7416.             $lastdaytoshowtime=$YearRequired."1231";                # Set day cursor to last day of last month of required year
  7417.         }
  7418.         else {
  7419.             $firstdaytocountaverage=$YearRequired.$MonthRequired."01";    # Set day cursor to 1st day of the required month
  7420.             $firstdaytoshowtime=$YearRequired.$MonthRequired."01";        # Set day cursor to 1st day of the required month
  7421.             $lastdaytocountaverage=$YearRequired.$MonthRequired."31";    # Set day cursor to last day of the required month
  7422.             $lastdaytoshowtime=$YearRequired.$MonthRequired."31";        # Set day cursor to last day of the required month
  7423.         }
  7424.     }
  7425.     if ($Debug) {
  7426.         debug("firstdaytocountaverage=$firstdaytocountaverage, lastdaytocountaverage=$lastdaytocountaverage",1);
  7427.         debug("firstdaytoshowtime=$firstdaytoshowtime, lastdaytoshowtime=$lastdaytoshowtime",1);
  7428.     }
  7429.  
  7430.     # Call to plugins' function AddHTMLContentHeader
  7431.     foreach my $pluginname (keys %{$PluginsLoaded{'AddHTMLContentHeader'}})  {
  7432.         my $function="AddHTMLContentHeader_$pluginname()";
  7433.         eval("$function");
  7434.     }
  7435.  
  7436.     # Output particular part
  7437.  
  7438. #    if ($HTMLOutput{'alldays'}) {
  7439. #        if ($Debug) { debug("ShowMonthDayStats",2); }
  7440. #        print "$Center<a name=\"monthday\"> </a><br />\n";
  7441. #        &tab_head("$Message[5]",0,0,"alldays");
  7442. #
  7443. #        my $NewLinkParams=${QueryString};
  7444. #        $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  7445. #        $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  7446. #        $NewLinkParams =~ s/(^|&)year=[^&]*//i;
  7447. #        $NewLinkParams =~ s/(^|&)month=[^&]*//i;
  7448. #        $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  7449. #        $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  7450. #        if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  7451. #        my $NewLinkTarget="";
  7452. #        if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; }
  7453. #
  7454. #        # Show monthly stats
  7455. #        print "<tr valign=\"bottom\"><td align=\"center\">";
  7456. #        print "<center>";
  7457. #
  7458. #        print "<table>";
  7459. #        print "<tr valign=\"bottom\"><td></td>";
  7460. #        $max_v=$max_p=$max_h=$max_k=1;
  7461. #        for (my $ix=1; $ix<=12; $ix++) {
  7462. #            my $monthix=sprintf("%02s",$ix);
  7463. #            #if ($MonthUnique{$YearRequired.$monthix} > $max_v) { $max_v=$MonthUnique{$YearRequired.$monthix}; }
  7464. #            if ($MonthVisits{$YearRequired.$monthix} > $max_v) { $max_v=$MonthVisits{$YearRequired.$monthix}; }
  7465. #            #if ($MonthPages{$YearRequired.$monthix} > $max_p)  { $max_p=$MonthPages{$YearRequired.$monthix}; }
  7466. #            if ($MonthHits{$YearRequired.$monthix} > $max_h)   { $max_h=$MonthHits{$YearRequired.$monthix}; }
  7467. #            if ($MonthBytes{$YearRequired.$monthix} > $max_k)  { $max_k=$MonthBytes{$YearRequired.$monthix}; }
  7468. #        }
  7469. #        for (my $ix=1; $ix<=12; $ix++) {
  7470. #            my $monthix=sprintf("%02s",$ix);
  7471. #            my $bredde_u=0; my $bredde_v=0;my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  7472. #            if ($max_v > 0) { $bredde_u=int($MonthUnique{$YearRequired.$monthix}/$max_v*$BarHeight)+1; }
  7473. #            if ($max_v > 0) { $bredde_v=int($MonthVisits{$YearRequired.$monthix}/$max_v*$BarHeight)+1; }
  7474. #            if ($max_h > 0) { $bredde_p=int($MonthPages{$YearRequired.$monthix}/$max_h*$BarHeight)+1; }
  7475. #            if ($max_h > 0) { $bredde_h=int($MonthHits{$YearRequired.$monthix}/$max_h*$BarHeight)+1; }
  7476. #            if ($max_k > 0) { $bredde_k=int($MonthBytes{$YearRequired.$monthix}/$max_k*$BarHeight)+1; }
  7477. #            print "<td>";
  7478. #            if ($ShowMonthDayStats =~ /U/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vu'}\" height=\"$bredde_u\" width=\"8\"".AltTitle("$Message[11]: $MonthUnique{$YearRequired.$monthix}")." />"; }
  7479. #            if ($ShowMonthDayStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"8\"".AltTitle("$Message[10]: $MonthVisits{$YearRequired.$monthix}")." />"; }
  7480. #            print " ";
  7481. #            if ($ShowMonthDayStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"8\"".AltTitle("$Message[56]: $MonthPages{$YearRequired.$monthix}")." />"; }
  7482. #            if ($ShowMonthDayStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"8\"".AltTitle("$Message[57]: $MonthHits{$YearRequired.$monthix}")." />"; }
  7483. #            if ($ShowMonthDayStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"8\"".AltTitle("$Message[75]: ".Format_Bytes($MonthBytes{$YearRequired.$monthix}))." />"; }
  7484. #            print "</td>\n";
  7485. #        }
  7486. #        print "</tr>\n";
  7487. #        # Show lib for month
  7488. #        print "<tr valign=\"middle\" cellspacing=\"0\" cellpadding=\"0\"><td></td>";
  7489. #        for (my $ix=1; $ix<=12; $ix++) {
  7490. #            my $monthix=($ix<10?"0$ix":"$ix");
  7491. #            print "<td>";
  7492. #            if (($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) && ! $HTMLOutput{'alldays'}) { print "<a href=\"".XMLEncode($AWScript?${NewLinkParams}year=$YearRequired&month=$monthix)."\"$NewLinkTarget>"; }
  7493. #            print "$MonthNumLib{$monthix}";
  7494. #            if (($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) && ! $HTMLOutput{'alldays'}) { print "</a>"; }
  7495. #            print "</td>\n";
  7496. #        }
  7497. #        print "</tr>\n";
  7498. #        print "</table>\n<br />\n";
  7499. #
  7500. #        # Show data array for month
  7501. #        print "<table>\n";
  7502. #        print "<tr><td width=\"15%\" bgcolor=\"#$color_TableBGRowTitle\">$Message[5]</td>";
  7503. #        if ($ShowMonthDayStats =~ /U/i) { print "<td width=\"17%\" bgcolor=\"#$color_u\" onmouseover=\"ShowTip(2,2);\">$Message[11]</td>"; }
  7504. #        if ($ShowMonthDayStats =~ /V/i) { print "<td width=\"17%\" bgcolor=\"#$color_v\" onmouseover=\"ShowTip(1,1);\">$Message[10]</td>"; }
  7505. #        if ($ShowMonthDayStats =~ /P/i) { print "<td width=\"17%\" bgcolor=\"#$color_p\" onmouseover=\"ShowTip(3,3);\">$Message[56]</td>"; }
  7506. #        if ($ShowMonthDayStats =~ /H/i) { print "<td width=\"17%\" bgcolor=\"#$color_h\" onmouseover=\"ShowTip(4,4);\">$Message[57]</td>"; }
  7507. #        if ($ShowMonthDayStats =~ /B/i) { print "<td width=\"17%\" bgcolor=\"#$color_k\" onmouseover=\"ShowTip(5,5);\">$Message[75]</td>"; }
  7508. #        print "</tr>\n";
  7509. #        for (my $ix=1; $ix<=12; $ix++) {
  7510. #            my $monthix=($ix<10?"0$ix":"$ix");
  7511. #            print "<tr>";
  7512. #            print "<td>",$MonthNumLib{$monthix},"</td>";
  7513. #            if ($ShowMonthDayStats =~ /U/i) { print "<td>",$MonthUnique{$YearRequired.$monthix}?$MonthUnique{$YearRequired.$monthix}:"0","</td>"; }
  7514. #            if ($ShowMonthDayStats =~ /V/i) { print "<td>",$MonthVisits{$YearRequired.$monthix}?$MonthVisits{$YearRequired.$monthix}:"0","</td>"; }
  7515. #            if ($ShowMonthDayStats =~ /P/i) { print "<td>",$MonthPages{$YearRequired.$monthix}?$MonthPages{$YearRequired.$monthix}:"0","</td>"; }
  7516. #            if ($ShowMonthDayStats =~ /H/i) { print "<td>",$MonthHits{$YearRequired.$monthix}?$MonthHits{$YearRequired.$monthix}:"0","</td>"; }
  7517. #            if ($ShowMonthDayStats =~ /B/i) { print "<td>",Format_Bytes(int($MonthBytes{$YearRequired.$monthix})),"</td>"; }
  7518. #            print "</tr>\n";
  7519. #        }
  7520. #        print "</table>\n<br />";
  7521. #
  7522. #        print "</center>\n";
  7523. #        print "</td></tr>\n";
  7524. #        &tab_end();
  7525. #
  7526. #        print "<br />\n";
  7527. #
  7528. #        &tab_head("$Message[4]",0,0,"");
  7529. #        print "<tr valign=\"bottom\"><td align=\"center\">";
  7530. #        print "<center>";
  7531. #
  7532. #        print "<table>";
  7533. #        print "<tr valign=\"bottom\"><td></td>";
  7534. #        # Get max_v, max_h and max_k values
  7535. #        $max_v=$max_h=$max_k=0;        # Start from 0 because can be lower than 1
  7536. #        foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  7537. #            $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  7538. #            my $year=$1; my $month=$2; my $day=$3;
  7539. #            if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  7540. #            if (($DayVisits{$year.$month.$day}||0) > $max_v)  { $max_v=$DayVisits{$year.$month.$day}; }
  7541. #            #if (($DayPages{$year.$month.$day}||0) > $max_p)  { $max_p=$DayPages{$year.$month.$day}; }
  7542. #            if (($DayHits{$year.$month.$day}||0) > $max_h)   { $max_h=$DayHits{$year.$month.$day}; }
  7543. #            if (($DayBytes{$year.$month.$day}||0) > $max_k)  { $max_k=$DayBytes{$year.$month.$day}; }
  7544. #        }
  7545. #        # Calculate average values
  7546. #        my $average_nb=0; my $average_v=0; my $average_p=0; my $average_h=0; my $average_k=0;
  7547. #        foreach my $daycursor ($firstdaytocountaverage..$lastdaytocountaverage) {
  7548. #            $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  7549. #            my $year=$1; my $month=$2; my $day=$3;
  7550. #            if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  7551. #            $average_nb++;                                            # Increase number of day used to count
  7552. #            $average_v+=($DayVisits{$daycursor}||0);
  7553. #            $average_p+=($DayPages{$daycursor}||0);
  7554. #            $average_h+=($DayHits{$daycursor}||0);
  7555. #            $average_k+=($DayBytes{$daycursor}||0);
  7556. #        }
  7557. #        if ($average_nb) {
  7558. #            $average_v=$average_v/$average_nb;
  7559. #            $average_p=$average_p/$average_nb;
  7560. #            $average_h=$average_h/$average_nb;
  7561. #            $average_k=$average_k/$average_nb;
  7562. #            if ($average_v > $max_v) { $max_v=$average_v; }
  7563. #            #if ($average_p > $max_p) { $max_p=$average_p; }
  7564. #            if ($average_h > $max_h) { $max_h=$average_h; }
  7565. #            if ($average_k > $max_k) { $max_k=$average_k; }
  7566. #        }
  7567. #        else {
  7568. #            $average_v="?";
  7569. #            $average_p="?";
  7570. #            $average_h="?";
  7571. #            $average_k="?";
  7572. #        }
  7573. #        foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  7574. #            $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  7575. #            my $year=$1; my $month=$2; my $day=$3;
  7576. #            if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  7577. #            my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0;
  7578. #            if ($max_v > 0) { $bredde_v=int(($DayVisits{$year.$month.$day}||0)/$max_v*$BarHeight)+1; }
  7579. #            if ($max_h > 0) { $bredde_p=int(($DayPages{$year.$month.$day}||0)/$max_h*$BarHeight)+1; }
  7580. #            if ($max_h > 0) { $bredde_h=int(($DayHits{$year.$month.$day}||0)/$max_h*$BarHeight)+1; }
  7581. #            if ($max_k > 0) { $bredde_k=int(($DayBytes{$year.$month.$day}||0)/$max_k*$BarHeight)+1; }
  7582. #            print "<td>";
  7583. #            if ($ShowMonthDayStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"4\"".AltTitle("$Message[10]: ".int($DayVisits{$year.$month.$day}||0))." />"; }
  7584. #            if ($ShowMonthDayStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"4\"".AltTitle("$Message[56]: ".int($DayPages{$year.$month.$day}||0))." />"; }
  7585. #            if ($ShowMonthDayStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"4\"".AltTitle("$Message[57]: ".int($DayHits{$year.$month.$day}||0))." />"; }
  7586. #            if ($ShowMonthDayStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"4\"".AltTitle("$Message[75]: ".Format_Bytes($DayBytes{$year.$month.$day}))." />"; }
  7587. #            print "</td>\n";
  7588. #        }
  7589. #        print "<td> </td>";
  7590. #        print "<td>";    # Show average value cell
  7591. #        my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0;
  7592. #        if ($max_v > 0) { $bredde_v=int($average_v/$max_v*$BarHeight)+1; }
  7593. #        if ($max_h > 0) { $bredde_p=int($average_p/$max_h*$BarHeight)+1; }
  7594. #        if ($max_h > 0) { $bredde_h=int($average_h/$max_h*$BarHeight)+1; }
  7595. #        if ($max_k > 0) { $bredde_k=int($average_k/$max_k*$BarHeight)+1; }
  7596. #        $average_v=sprintf("%.2f",$average_v);
  7597. #        $average_p=sprintf("%.2f",$average_p);
  7598. #        $average_h=sprintf("%.2f",$average_h);
  7599. #        $average_k=sprintf("%.2f",$average_k);
  7600. #        if ($ShowMonthDayStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"4\"".AltTitle("$Message[10]: $average_v")." />"; }
  7601. #        if ($ShowMonthDayStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"4\"".AltTitle("$Message[56]: $average_p")." />"; }
  7602. #        if ($ShowMonthDayStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"4\"".AltTitle("$Message[57]: $average_h")." />"; }
  7603. #        if ($ShowMonthDayStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"4\"".AltTitle("$Message[75]: ".Format_Bytes($average_k))." />"; }
  7604. #        print "</td>";
  7605. #        print "<td></td>\n";
  7606. #        print "</tr>\n";
  7607. #        # Show lib for days
  7608. #        print "<tr><td></td>";
  7609. #        foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  7610. #            $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  7611. #            my $year=$1; my $month=$2; my $day=$3;
  7612. #            if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  7613. #            my $dayofweekcursor=DayOfWeek($day,$month,$year);
  7614. #            print "<td valign=\"middle\"".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">";
  7615. #            print ($day==$nowday && $month==$nowmonth && $year==$nowyear?'<b>':'');
  7616. #            print "$day<br /><span style=\"font-size: ".($FrameName ne 'mainright'?"10":"9")."px;\">".$MonthNumLib{$month}."</span>";
  7617. #            print ($day==$nowday && $month==$nowmonth && $year==$nowyear?'</b>':'');
  7618. #            print "</td>\n";
  7619. #        }
  7620. #        print "<td> </td>";
  7621. #        print "<td valign=\"middle\"".Tooltip(18).">$Message[96]</td>\n";
  7622. #        print "<td></td>\n";
  7623. #        print "</tr>\n";
  7624. #        print "</table>\n<br />\n";
  7625. #
  7626. #        # Show data array for days
  7627. #        print "<table>\n";
  7628. #        print "<tr><td width=\"20%\" bgcolor=\"#$color_TableBGRowTitle\">$Message[4]</td>";
  7629. #        if ($ShowMonthDayStats =~ /V/i) { print "<td width=\"20%\" bgcolor=\"#$color_v\"".Tooltip(1).">$Message[10]</td>"; }
  7630. #        if ($ShowMonthDayStats =~ /P/i) { print "<td width=\"20%\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  7631. #        if ($ShowMonthDayStats =~ /H/i) { print "<td width=\"20%\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  7632. #        if ($ShowMonthDayStats =~ /B/i) { print "<td width=\"20%\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; }
  7633. #        print "</tr>\n";
  7634. #        foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  7635. #            $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  7636. #            my $year=$1; my $month=$2; my $day=$3;
  7637. #            if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  7638. #            my $dayofweekcursor=DayOfWeek($day,$month,$year);
  7639. #            print "<tr>";
  7640. #            print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">",Format_Date("$year$month$day"."000000",2),"</td>";
  7641. #            if ($ShowMonthDayStats =~ /V/i) { print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">",$DayVisits{$year.$month.$day}?$DayVisits{$year.$month.$day}:"0","</td>"; }
  7642. #            if ($ShowMonthDayStats =~ /P/i) { print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">",$DayPages{$year.$month.$day}?$DayPages{$year.$month.$day}:"0","</td>"; }
  7643. #            if ($ShowMonthDayStats =~ /H/i) { print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">",$DayHits{$year.$month.$day}?$DayHits{$year.$month.$day}:"0","</td>"; }
  7644. #            if ($ShowMonthDayStats =~ /B/i) { print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">",Format_Bytes(int($DayBytes{$year.$month.$day})),"</td>"; }
  7645. #            print "</tr>\n";
  7646. #        }
  7647. #        print "</table>\n<br />";
  7648. #
  7649. #        print "</center>\n";
  7650. #        print "</td></tr>\n";
  7651. #        &tab_end();
  7652. #        &html_end;
  7653. #        exit(0);
  7654. #    }
  7655.     if ($HTMLOutput{'alldomains'}) {
  7656.         print "$Center<a name=\"domains\"> </a><br />\n";
  7657.         # Show domains list
  7658.         my $title=''; my $cpt=0;
  7659.         if ($HTMLOutput{'alldomains'})  { $title.="$Message[25]"; $cpt=(scalar keys %_domener_h); }
  7660.         &tab_head("$title",19,0,'domains');
  7661.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"$WIDTHCOLICON\"> </th><th colspan=\"2\">$Message[17]</th>";
  7662.         if ($ShowDomainsStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th>"; }
  7663.         if ($ShowDomainsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  7664.         if ($ShowDomainsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  7665.         print "<th> </th>";
  7666.         print "</tr>\n";
  7667.         $total_p=$total_h=$total_k=0;
  7668.         $max_h=1; foreach (values %_domener_h) { if ($_ > $max_h) { $max_h = $_; } }
  7669.         $max_k=1; foreach (values %_domener_k) { if ($_ > $max_k) { $max_k = $_; } }
  7670.         my $count=0;
  7671.         &BuildKeyList($MaxRowsInHTMLOutput,1,\%_domener_h,\%_domener_p);
  7672.         foreach my $key (@keylist) {
  7673.             my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  7674.             if ($max_h > 0) { $bredde_p=int($BarWidth*$_domener_p{$key}/$max_h)+1; }    # use max_h to enable to compare pages with hits
  7675.             if ($_domener_p{$key} && $bredde_p==1) { $bredde_p=2; }
  7676.             if ($max_h > 0) { $bredde_h=int($BarWidth*$_domener_h{$key}/$max_h)+1; }
  7677.             if ($_domener_h{$key} && $bredde_h==1) { $bredde_h=2; }
  7678.             if ($max_k > 0) { $bredde_k=int($BarWidth*($_domener_k{$key}||0)/$max_k)+1; }
  7679.             if ($_domener_k{$key} && $bredde_k==1) { $bredde_k=2; }
  7680.             my $newkey=lc($key);
  7681.             if ($newkey eq 'ip' || ! $DomainsHashIDLib{$newkey}) {
  7682.                 print "<tr><td width=\"$WIDTHCOLICON\"><img src=\"$DirIcons\/flags\/ip.png\" height=\"14\"".AltTitle("$Message[0]")." /></td><td class=\"aws\">$Message[0]</td><td>$newkey</td>";
  7683.             }
  7684.             else {
  7685.                 print "<tr><td width=\"$WIDTHCOLICON\"><img src=\"$DirIcons\/flags\/$newkey.png\" height=\"14\"".AltTitle("$newkey")." /></td><td class=\"aws\">$DomainsHashIDLib{$newkey}</td><td>$newkey</td>";
  7686.             }
  7687.             if ($ShowDomainsStats =~ /P/i) { print "<td>$_domener_p{$key}</td>"; }
  7688.             if ($ShowDomainsStats =~ /H/i) { print "<td>$_domener_h{$key}</td>"; }
  7689.             if ($ShowDomainsStats =~ /B/i) { print "<td>".Format_Bytes($_domener_k{$key})."</td>"; }
  7690.             print "<td style=\"text-align:left; font-size:4px;\">";
  7691.             if ($ShowDomainsStats =~ /P/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hp'}\" width=\"$bredde_p\" height=\"5\"".AltTitle("$Message[56]: ".int($_domener_p{$key}))." /><br />\n"; }
  7692.             if ($ShowDomainsStats =~ /H/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\"".AltTitle("$Message[57]: ".int($_domener_h{$key}))." /><br />\n"; }
  7693.             if ($ShowDomainsStats =~ /B/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hk'}\" width=\"$bredde_k\" height=\"5\"".AltTitle("$Message[75]: ".Format_Bytes($_domener_k{$key}))." />"; }
  7694.             print "</td>";
  7695.             print "</tr>\n";
  7696.             $total_p += $_domener_p{$key};
  7697.             $total_h += $_domener_h{$key};
  7698.             $total_k += $_domener_k{$key}||0;
  7699.             $count++;
  7700.         }
  7701.         $rest_p=$TotalPages-$total_p;
  7702.         $rest_h=$TotalHits-$total_h;
  7703.         $rest_k=$TotalBytes-$total_k;
  7704.         if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {     # All other domains (known or not)
  7705.             print "<tr><td width=\"$WIDTHCOLICON\"> </td><td colspan=\"2\" class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  7706.             if ($ShowDomainsStats =~ /P/i) { print "<td>$rest_p</td>"; }
  7707.             if ($ShowDomainsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  7708.             if ($ShowDomainsStats =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  7709.             print "<td class=\"aws\"> </td>";
  7710.             print "</tr>\n";
  7711.         }
  7712.         &tab_end();
  7713.         &html_end(1);
  7714.     }
  7715.     if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) {
  7716.         print "$Center<a name=\"hosts\"> </a><br />\n";
  7717.         # Show filter form
  7718.         &ShowFormFilter("hostfilter",$FilterIn{'host'},$FilterEx{'host'});
  7719.         # Show hosts list
  7720.         my $title=''; my $cpt=0;
  7721.         if ($HTMLOutput{'allhosts'})  { $title.="$Message[81]"; $cpt=(scalar keys %_host_h); }
  7722.         if ($HTMLOutput{'lasthosts'}) { $title.="$Message[9]"; $cpt=(scalar keys %_host_h); }
  7723.         &tab_head("$title",19,0,'hosts');
  7724.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>";
  7725.         if ($FilterIn{'host'} || $FilterEx{'host'}) {    # With filter
  7726.             if ($FilterIn{'host'}) { print "$Message[79] '<b>$FilterIn{'host'}</b>'"; }
  7727.             if ($FilterIn{'host'} && $FilterEx{'host'}) { print " - "; }
  7728.             if ($FilterEx{'host'}) { print " Exlude $Message[79] '<b>$FilterEx{'host'}</b>'"; }
  7729.             if ($FilterIn{'host'} || $FilterEx{'host'}) { print ": "; }
  7730.             print "$cpt $Message[81]";
  7731.             if ($MonthRequired ne 'all') {
  7732.                 if ($HTMLOutput{'allhosts'} || $HTMLOutput{'lasthosts'}) { print "<br />$Message[102]: $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1] - $TotalUnique $Message[11]"; }
  7733.             }
  7734.         }
  7735.         else {    # Without filter
  7736.             if ($MonthRequired ne 'all') { print "$Message[102] : $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1] - $TotalUnique $Message[11]"; }
  7737.             else { print "$Message[102] : ".(scalar keys %_host_h); }
  7738.         }
  7739.         print "</th>";
  7740.         &ShowHostInfo('__title__');
  7741.         if ($ShowHostsStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th>"; }
  7742.         if ($ShowHostsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  7743.         if ($ShowHostsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  7744.         if ($ShowHostsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  7745.         print "</tr>\n";
  7746.         $total_p=$total_h=$total_k=0;
  7747.         my $count=0;
  7748.         if ($HTMLOutput{'allhosts'})  { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_p); }
  7749.         if ($HTMLOutput{'lasthosts'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_l); }
  7750.         foreach my $key (@keylist) {
  7751.             my $host=CleanFromCSSA($key);
  7752.             print "<tr><td class=\"aws\">".($_robot_l{$key}?'<b>':'')."$host".($_robot_l{$key}?'</b>':'')."</td>";
  7753.             &ShowHostInfo($key);
  7754.             if ($ShowHostsStats =~ /P/i) { print "<td>".($_host_p{$key}?$_host_p{$key}:" ")."</td>"; }
  7755.             if ($ShowHostsStats =~ /H/i) { print "<td>$_host_h{$key}</td>"; }
  7756.             if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($_host_k{$key})."</td>"; }
  7757.             if ($ShowHostsStats =~ /L/i) { print "<td>".($_host_l{$key}?Format_Date($_host_l{$key},1):'-')."</td>"; }
  7758.             print "</tr>\n";
  7759.             $total_p += $_host_p{$key};
  7760.             $total_h += $_host_h{$key};
  7761.             $total_k += $_host_k{$key}||0;
  7762.             $count++;
  7763.         }
  7764.         if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); }
  7765.         $rest_p=$TotalPages-$total_p;
  7766.         $rest_h=$TotalHits-$total_h;
  7767.         $rest_k=$TotalBytes-$total_k;
  7768.         if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other visitors (known or not)
  7769.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  7770.             &ShowHostInfo('');
  7771.             if ($ShowHostsStats =~ /P/i) { print "<td>".($rest_p?$rest_p:" ")."</td>"; }
  7772.             if ($ShowHostsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  7773.             if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  7774.             if ($ShowHostsStats =~ /L/i) { print "<td> </td>"; }
  7775.             print "</tr>\n";
  7776.         }
  7777.         &tab_end();
  7778.         &html_end(1);
  7779.     }
  7780.     if ($HTMLOutput{'unknownip'}) {
  7781.         print "$Center<a name=\"unknownip\"> </a><br />\n";
  7782.         &tab_head("$Message[45]",19,0,'unknownwip');
  7783.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>".(scalar keys %_host_h)." $Message[1]</th>";
  7784.         &ShowHostInfo('__title__');
  7785.         if ($ShowHostsStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th>"; }
  7786.         if ($ShowHostsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  7787.         if ($ShowHostsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  7788.         if ($ShowHostsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  7789.         print "</tr>\n";
  7790.         $total_p=$total_h=$total_k=0;
  7791.         my $count=0;
  7792.         &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_host_h,\%_host_p);
  7793.         foreach my $key (@keylist) {
  7794.             my $host=CleanFromCSSA($key);
  7795.             print "<tr><td class=\"aws\">$host</td>";
  7796.             &ShowHostInfo($key);
  7797.             if ($ShowHostsStats =~ /P/i) { print "<td>".($_host_p{$key}?$_host_p{$key}:" ")."</td>"; }
  7798.             if ($ShowHostsStats =~ /H/i) { print "<td>$_host_h{$key}</td>"; }
  7799.             if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($_host_k{$key})."</td>"; }
  7800.             if ($ShowHostsStats =~ /L/i) { print "<td>".($_host_l{$key}?Format_Date($_host_l{$key},1):'-')."</td>"; }
  7801.             print "</tr>\n";
  7802.             $total_p += $_host_p{$key};
  7803.             $total_h += $_host_h{$key};
  7804.             $total_k += $_host_k{$key}||0;
  7805.             $count++;
  7806.         }
  7807.         if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); }
  7808.         $rest_p=$TotalPages-$total_p;
  7809.         $rest_h=$TotalHits-$total_h;
  7810.         $rest_k=$TotalBytes-$total_k;
  7811.         if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other visitors (known or not)
  7812.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[82]</span></td>";
  7813.             &ShowHostInfo('');
  7814.             if ($ShowHostsStats =~ /P/i) { print "<td>".($rest_p?$rest_p:" ")."</td>"; }
  7815.             if ($ShowHostsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  7816.             if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  7817.             if ($ShowHostsStats =~ /L/i) { print "<td> </td>"; }
  7818.             print "</tr>\n";
  7819.         }
  7820.         &tab_end();
  7821.         &html_end(1);
  7822.     }
  7823.     if ($HTMLOutput{'allemails'} || $HTMLOutput{'lastemails'}) {
  7824.         &ShowEmailSendersChart($NewLinkParams,$NewLinkTarget);
  7825.         &html_end(1);
  7826.     }
  7827.     if ($HTMLOutput{'allemailr'} || $HTMLOutput{'lastemailr'}) {
  7828.         &ShowEmailReceiversChart($NewLinkParams,$NewLinkTarget);
  7829.         &html_end(1);
  7830.     }
  7831.     if ($HTMLOutput{'alllogins'} || $HTMLOutput{'lastlogins'}) {
  7832.         print "$Center<a name=\"logins\"> </a><br />\n";
  7833.         my $title='';
  7834.         if ($HTMLOutput{'alllogins'}) { $title.="$Message[94]"; }
  7835.         if ($HTMLOutput{'lastlogins'}) { $title.="$Message[9]"; }
  7836.         &tab_head("$title",19,0,'logins');
  7837.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$Message[94] : ".(scalar keys %_login_h)."</th>";
  7838.         &ShowUserInfo('__title__');
  7839.         if ($ShowAuthenticatedUsers =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th>"; }
  7840.         if ($ShowAuthenticatedUsers =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  7841.         if ($ShowAuthenticatedUsers =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  7842.         if ($ShowAuthenticatedUsers =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  7843.         print "</tr>\n";
  7844.         $total_p=$total_h=$total_k=0;
  7845.         my $count=0;
  7846.         if ($HTMLOutput{'alllogins'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_login_h,\%_login_p); }
  7847.         if ($HTMLOutput{'lastlogins'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Host'},\%_login_h,\%_login_l); }
  7848.         foreach my $key (@keylist) {
  7849.             print "<tr><td class=\"aws\">$key</td>";
  7850.             &ShowUserInfo($key);
  7851.             if ($ShowAuthenticatedUsers =~ /P/i) { print "<td>".($_login_p{$key}?$_login_p{$key}:" ")."</td>"; }
  7852.             if ($ShowAuthenticatedUsers =~ /H/i) { print "<td>$_login_h{$key}</td>"; }
  7853.             if ($ShowAuthenticatedUsers =~ /B/i) { print "<td>".Format_Bytes($_login_k{$key})."</td>"; }
  7854.             if ($ShowAuthenticatedUsers =~ /L/i) { print "<td>".($_login_l{$key}?Format_Date($_login_l{$key},1):'-')."</td>"; }
  7855.             print "</tr>\n";
  7856.             $total_p += $_login_p{$key}||0;
  7857.             $total_h += $_login_h{$key};
  7858.             $total_k += $_login_k{$key}||0;
  7859.             $count++;
  7860.         }
  7861.         if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalHits / $total_h - $TotalBytes / $total_h",2); }
  7862.         $rest_p=$TotalPages-$total_p;
  7863.         $rest_h=$TotalHits-$total_h;
  7864.         $rest_k=$TotalBytes-$total_k;
  7865.         if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other logins and/or anonymous
  7866.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[125]</span></td>";
  7867.             &ShowUserInfo('');
  7868.             if ($ShowAuthenticatedUsers =~ /P/i) { print "<td>".($rest_p?$rest_p:" ")."</td>"; }
  7869.             if ($ShowAuthenticatedUsers =~ /H/i) { print "<td>$rest_h</td>"; }
  7870.             if ($ShowAuthenticatedUsers =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  7871.             if ($ShowAuthenticatedUsers =~ /L/i) { print "<td> </td>"; }
  7872.             print "</tr>\n";
  7873.         }
  7874.         &tab_end();
  7875.         &html_end(1);
  7876.     }
  7877.     if ($HTMLOutput{'allrobots'} || $HTMLOutput{'lastrobots'}) {
  7878.         print "$Center<a name=\"robots\"> </a><br />\n";
  7879.         my $title='';
  7880.         if ($HTMLOutput{'allrobots'})  { $title.="$Message[53]"; }
  7881.         if ($HTMLOutput{'lastrobots'}) { $title.="$Message[9]"; }
  7882.         &tab_head("$title",19,0,'robots');
  7883.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>".(scalar keys %_robot_h)." $Message[51]</th>";
  7884.         if ($ShowRobotsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  7885.         if ($ShowRobotsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  7886.         if ($ShowRobotsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  7887.         print "</tr>\n";
  7888.         $total_p=$total_h=$total_k=$total_r=0;
  7889.         my $count=0;
  7890.         if ($HTMLOutput{'allrobots'})  { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Robot'},\%_robot_h,\%_robot_h); }
  7891.         if ($HTMLOutput{'lastrobots'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Robot'},\%_robot_h,\%_robot_l); }
  7892.         foreach my $key (@keylist) {
  7893.             print "<tr><td class=\"aws\">".($RobotsHashIDLib{$key}?$RobotsHashIDLib{$key}:$key)."</td>";
  7894.             if ($ShowRobotsStats =~ /H/i) { print "<td>".($_robot_h{$key}-$_robot_r{$key}).($_robot_r{$key}?"+$_robot_r{$key}":"")."</td>"; }
  7895.             if ($ShowRobotsStats =~ /B/i) { print "<td>".Format_Bytes($_robot_k{$key})."</td>"; }
  7896.             if ($ShowRobotsStats =~ /L/i) { print "<td>".($_robot_l{$key}?Format_Date($_robot_l{$key},1):'-')."</td>"; }
  7897.             print "</tr>\n";
  7898.             #$total_p += $_robot_p{$key}||0;
  7899.             $total_h += $_robot_h{$key};
  7900.             $total_k += $_robot_k{$key}||0;
  7901.             $total_r += $_robot_r{$key}||0;
  7902.             $count++;
  7903.         }
  7904.         # For bots we need to count Totals
  7905.         my $TotalPagesRobots = 0; #foreach (values %_robot_p) { $TotalPagesRobots+=$_; }
  7906.         my $TotalHitsRobots = 0; foreach (values %_robot_h) { $TotalHitsRobots+=$_; }
  7907.         my $TotalBytesRobots = 0; foreach (values %_robot_k) { $TotalBytesRobots+=$_; }
  7908.         my $TotalRRobots = 0; foreach (values %_robot_r) { $TotalRRobots+=$_; }
  7909.         $rest_p=0;    #$rest_p=$TotalPagesRobots-$total_p;
  7910.         $rest_h=$TotalHitsRobots-$total_h;
  7911.         $rest_k=$TotalBytesRobots-$total_k;
  7912.         $rest_r=$TotalRRobots-$total_r;
  7913.         if ($Debug) { debug("Total real / shown : $TotalPagesRobots / $total_p - $TotalHitsRobots / $total_h - $TotalBytesRobots / $total_k",2); }
  7914.         if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0) {    # All other robots
  7915.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  7916.             if ($ShowRobotsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  7917.             if ($ShowRobotsStats =~ /B/i) { print "<td>".(Format_Bytes($rest_k))."</td>"; }
  7918.             if ($ShowRobotsStats =~ /L/i) { print "<td> </td>"; }
  7919.             print "</tr>\n";
  7920.         }
  7921.         &tab_end("* $Message[156]".($TotalRRobots?" $Message[157]":""));
  7922.         &html_end(1);
  7923.     }
  7924.     if ($HTMLOutput{'urldetail'} || $HTMLOutput{'urlentry'} || $HTMLOutput{'urlexit'}) {
  7925.         # Call to plugins' function ShowPagesFilter
  7926.         foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesFilter'}})  {
  7927.             my $function="ShowPagesFilter_$pluginname()";
  7928.             eval("$function");
  7929.         }
  7930.         print "$Center<a name=\"urls\"> </a><br />\n";
  7931.         # Show filter form
  7932.         &ShowFormFilter("urlfilter",$FilterIn{'url'},$FilterEx{'url'});
  7933.         # Show URL list
  7934.         my $title=''; my $cpt=0;
  7935.         if ($HTMLOutput{'urldetail'}) { $title=$Message[19]; $cpt=(scalar keys %_url_p); }
  7936.         if ($HTMLOutput{'urlentry'})  { $title=$Message[104]; $cpt=(scalar keys %_url_e); }
  7937.         if ($HTMLOutput{'urlexit'})   { $title=$Message[116]; $cpt=(scalar keys %_url_x); }
  7938.         &tab_head("$title",19,0,'urls');
  7939.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>";
  7940.         if ($FilterIn{'url'} || $FilterEx{'url'}) {
  7941.             if ($FilterIn{'url'}) { print "$Message[79] <b>$FilterIn{'url'}</b>"; }
  7942.             if ($FilterIn{'url'} && $FilterEx{'url'}) { print " - "; }
  7943.             if ($FilterEx{'url'}) { print "Exclude $Message[79] <b>$FilterEx{'url'}</b>"; }
  7944.             if ($FilterIn{'url'} || $FilterEx{'url'}) { print ": "; }
  7945.             print "$cpt $Message[28]";
  7946.             if ($MonthRequired ne 'all') {
  7947.                 if ($HTMLOutput{'urldetail'}) { print "<br />$Message[102]: $TotalDifferentPages $Message[28]"; }
  7948.             }
  7949.         }
  7950.         else { print "$Message[102]: $cpt $Message[28]"; }
  7951.         print "</th>";
  7952.         if ($ShowPagesStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[29]</th>"; }
  7953.         if ($ShowPagesStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[106]</th>"; }
  7954.         if ($ShowPagesStats =~ /E/i) { print "<th bgcolor=\"#$color_e\" width=\"80\">$Message[104]</th>"; }
  7955.         if ($ShowPagesStats =~ /X/i) { print "<th bgcolor=\"#$color_x\" width=\"80\">$Message[116]</th>"; }
  7956.         # Call to plugins' function ShowPagesAddField
  7957.         foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  7958.             my $function="ShowPagesAddField_$pluginname('title')";
  7959.             eval("$function");
  7960.         }
  7961.         print "<th> </th></tr>\n";
  7962.         $total_p=$total_k=$total_e=$total_x=0;
  7963.         my $count=0;
  7964.         if ($HTMLOutput{'urlentry'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_e,\%_url_e); }
  7965.         elsif ($HTMLOutput{'urlexit'}) { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_x,\%_url_x); }
  7966.         else { &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'File'},\%_url_p,\%_url_p); }
  7967.         $max_p=1; $max_k=1;
  7968.         foreach my $key (@keylist) {
  7969.             if ($_url_p{$key} > $max_p) { $max_p = $_url_p{$key}; }
  7970.             if ($_url_k{$key}/($_url_p{$key}||1) > $max_k) { $max_k = $_url_k{$key}/($_url_p{$key}||1); }
  7971.         }
  7972.         foreach my $key (@keylist) {
  7973.             print "<tr><td class=\"aws\">";
  7974.             &ShowURLInfo($key);
  7975.             print "</td>";
  7976.             my $bredde_p=0; my $bredde_e=0; my $bredde_x=0; my $bredde_k=0;
  7977.             if ($max_p > 0) { $bredde_p=int($BarWidth*($_url_p{$key}||0)/$max_p)+1; }
  7978.             if (($bredde_p==1) && $_url_p{$key}) { $bredde_p=2; }
  7979.             if ($max_p > 0) { $bredde_e=int($BarWidth*($_url_e{$key}||0)/$max_p)+1; }
  7980.             if (($bredde_e==1) && $_url_e{$key}) { $bredde_e=2; }
  7981.             if ($max_p > 0) { $bredde_x=int($BarWidth*($_url_x{$key}||0)/$max_p)+1; }
  7982.             if (($bredde_x==1) && $_url_x{$key}) { $bredde_x=2; }
  7983.             if ($max_k > 0) { $bredde_k=int($BarWidth*(($_url_k{$key}||0)/($_url_p{$key}||1))/$max_k)+1; }
  7984.             if (($bredde_k==1) && $_url_k{$key}) { $bredde_k=2; }
  7985.             if ($ShowPagesStats =~ /P/i) { print "<td>$_url_p{$key}</td>"; }
  7986.             if ($ShowPagesStats =~ /B/i) { print "<td>".($_url_k{$key}?Format_Bytes($_url_k{$key}/($_url_p{$key}||1)):" ")."</td>"; }
  7987.             if ($ShowPagesStats =~ /E/i) { print "<td>".($_url_e{$key}?$_url_e{$key}:" ")."</td>"; }
  7988.             if ($ShowPagesStats =~ /X/i) { print "<td>".($_url_x{$key}?$_url_x{$key}:" ")."</td>"; }
  7989.             # Call to plugins' function ShowPagesAddField
  7990.             foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  7991.                 my $function="ShowPagesAddField_$pluginname('$key')"; 
  7992.                 eval("$function");
  7993.             }
  7994.             print "<td style=\"text-align:left; font-size:4px;\">";
  7995.             # alt and title are not provided to reduce page size
  7996.             if ($ShowPagesStats =~ /P/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hp'}\" width=\"$bredde_p\" height=\"4\" /><br />"; }
  7997.             if ($ShowPagesStats =~ /B/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hk'}\" width=\"$bredde_k\" height=\"4\" /><br />"; }
  7998.             if ($ShowPagesStats =~ /E/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'he'}\" width=\"$bredde_e\" height=\"4\" /><br />"; }
  7999.             if ($ShowPagesStats =~ /X/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hx'}\" width=\"$bredde_x\" height=\"4\" />"; }
  8000.             print "</td></tr>\n";
  8001.             $total_p += $_url_p{$key};
  8002.             $total_e += $_url_e{$key};
  8003.             $total_x += $_url_x{$key};
  8004.             $total_k += $_url_k{$key};
  8005.             $count++;
  8006.         }
  8007.         if ($Debug) { debug("Total real / shown : $TotalPages / $total_p - $TotalEntries / $total_e - $TotalExits / $total_x - $TotalBytesPages / $total_k",2); }
  8008.         $rest_p=$TotalPages-$total_p;
  8009.         $rest_k=$TotalBytesPages-$total_k;
  8010.         $rest_e=$TotalEntries-$total_e;
  8011.         $rest_x=$TotalExits-$total_x;
  8012.         if ($rest_p > 0 || $rest_e > 0 || $rest_k > 0) {
  8013.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  8014.             if ($ShowPagesStats =~ /P/i) { print "<td>".($rest_p?$rest_p:" ")."</td>"; }
  8015.             if ($ShowPagesStats =~ /B/i) { print "<td>".($rest_k?Format_Bytes($rest_k/($rest_p||1)):" ")."</td>"; }
  8016.             if ($ShowPagesStats =~ /E/i) { print "<td>".($rest_e?$rest_e:" ")."</td>"; }
  8017.             if ($ShowPagesStats =~ /X/i) { print "<td>".($rest_x?$rest_x:" ")."</td>"; }
  8018.             # Call to plugins' function ShowPagesAddField
  8019.             foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  8020.                 my $function="ShowPagesAddField_$pluginname('')";
  8021.                 eval("$function");
  8022.             }
  8023.             print "<td> </td></tr>\n";
  8024.         }
  8025.         &tab_end();
  8026.         &html_end(1);
  8027.     }
  8028.     if ($HTMLOutput{'unknownos'}) {
  8029.         print "$Center<a name=\"unknownos\"> </a><br />\n";
  8030.         my $title="$Message[46]";
  8031.         &tab_head("$title",19,0,'unknownos');
  8032.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>User agent (".(scalar keys %_unknownreferer_l).")</th><th>$Message[9]</th></tr>\n";
  8033.         $total_l=0;
  8034.         my $count=0;
  8035.         &BuildKeyList($MaxRowsInHTMLOutput,1,\%_unknownreferer_l,\%_unknownreferer_l);
  8036.         foreach my $key (@keylist) {
  8037.             my $useragent=CleanFromCSSA($key);
  8038.             print "<tr><td class=\"aws\">$useragent</td>";
  8039.             print "<td>".Format_Date($_unknownreferer_l{$key},1)."</td>";
  8040.             print "</tr>\n";
  8041.             $total_l+=1;
  8042.             $count++;
  8043.         }
  8044.         $rest_l=(scalar keys %_unknownreferer_l)-$total_l;
  8045.         if ($rest_l > 0) {
  8046.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  8047.             print "<td>-</td>";
  8048.             print "</tr>\n";
  8049.         }
  8050.         &tab_end();
  8051.         &html_end(1);
  8052.     }
  8053.     if ($HTMLOutput{'unknownbrowser'}) {
  8054.         print "$Center<a name=\"unknownbrowser\"> </a><br />\n";
  8055.         my $title="$Message[50]";
  8056.         &tab_head("$title",19,0,'unknownbrowser');
  8057.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>User agent (".(scalar keys %_unknownrefererbrowser_l).")</th><th>$Message[9]</th></tr>\n";
  8058.         $total_l=0;
  8059.         my $count=0;
  8060.         &BuildKeyList($MaxRowsInHTMLOutput,1,\%_unknownrefererbrowser_l,\%_unknownrefererbrowser_l);
  8061.         foreach my $key (@keylist) {
  8062.             my $useragent=CleanFromCSSA($key);
  8063.             print "<tr><td class=\"aws\">$useragent</td><td>".Format_Date($_unknownrefererbrowser_l{$key},1)."</td></tr>\n";
  8064.             $total_l+=1;
  8065.             $count++;
  8066.         }
  8067.         $rest_l=(scalar keys %_unknownrefererbrowser_l)-$total_l;
  8068.         if ($rest_l > 0) {
  8069.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  8070.             print "<td>-</td>";
  8071.             print "</tr>\n";
  8072.         }
  8073.         &tab_end();
  8074.         &html_end(1);
  8075.     }
  8076.     if ($HTMLOutput{'osdetail'}) {
  8077.         # Show os versions
  8078.         print "$Center<a name=\"osversions\"> </a><br />";
  8079.         my $title="$Message[59]";
  8080.         &tab_head("$title",19,0,'osversions');
  8081.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"2\">$Message[58]</th>";
  8082.         print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>";
  8083.         print "<th> </th>";
  8084.         print "</tr>\n";
  8085.         $total_h=0;
  8086.         my $count=0;
  8087.         &BuildKeyList(MinimumButNoZero(scalar keys %_os_h,500),1,\%_os_h,\%_os_h);
  8088.         my %keysinkeylist=();
  8089.         $max_h=1;
  8090.         # Count total by family
  8091.         my %totalfamily_h=();
  8092.         my $TotalFamily=0;
  8093.         OSLOOP: foreach my $key (@keylist) {
  8094.             $total_h+=$_os_h{$key};
  8095.             if ($_os_h{$key} > $max_h) { $max_h = $_os_h{$key}; }
  8096.             foreach my $family (@OSFamily) { if ($key =~ /^$family/i) { $totalfamily_h{$family}+=$_os_h{$key}; $TotalFamily+=$_os_h{$key}; next OSLOOP; } }
  8097.         }
  8098.         # Write records grouped in a browser family
  8099.         foreach my $family (@OSFamily) {
  8100.             my $p=' ';
  8101.             if ($total_h) { $p=int($totalfamily_h{$family}/$total_h*1000)/10; $p="$p %"; }
  8102.             my $familyheadershown=0;
  8103.             foreach my $key (reverse sort keys %_os_h) {
  8104.                 if ($key =~ /^$family(.*)/i) {
  8105.                     if (! $familyheadershown) {
  8106.                         print "<tr bgcolor=\"#F6F6F6\"><td class=\"aws\" colspan=\"2\"><b>".uc($family)."</b></td>";
  8107.                         print "<td><b>".int($totalfamily_h{$family})."</b></td><td><b>$p</b></td><td> </td>";
  8108.                         print "</tr>\n";
  8109.                         $familyheadershown=1;
  8110.                     }
  8111.                     $keysinkeylist{$key}=1;
  8112.                     my $ver=$1;
  8113.                     my $p=' ';
  8114.                     if ($total_h) { $p=int($_os_h{$key}/$total_h*1000)/10; $p="$p %"; }
  8115.                     print "<tr>";
  8116.                     print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/os\/$key.png\"".AltTitle("")." /></td>";
  8117.                     print "<td class=\"aws\">$OSHashLib{$key}</td>";
  8118.                     my $bredde_h=0;
  8119.                     if ($max_h > 0) { $bredde_h=int($BarWidth*($_os_h{$key}||0)/$max_h)+1; }
  8120.                     if (($bredde_h==1) && $_os_h{$key}) { $bredde_h=2; }
  8121.                     print "<td>$_os_h{$key}</td><td>$p</td>";
  8122.                     print "<td class=\"aws\">";
  8123.                     # alt and title are not provided to reduce page size
  8124.                     if ($ShowOSStats) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\" /><br />"; }
  8125.                     print "</td>";
  8126.                     print "</tr>\n";
  8127.                     $count++;
  8128.                 }
  8129.             }
  8130.         }
  8131.         # Write other records
  8132.         my $familyheadershown=0;
  8133.         foreach my $key (@keylist) {
  8134.             if ($keysinkeylist{$key}) { next; }
  8135.             if (! $familyheadershown) {
  8136.                 my $p=' ';
  8137.                 if ($total_h) { $p=int(($total_h-$TotalFamily)/$total_h*1000)/10; $p="$p %"; }
  8138.                 print "<tr bgcolor=\"#F6F6F6\"><td class=\"aws\" colspan=\"2\"><b>".uc($Message[2])."</b></td>";
  8139.                 print "<td><b>".($total_h-$TotalFamily)."</b></td><td><b>$p</b></td><td> </td>";
  8140.                 print "</tr>\n";
  8141.                 $familyheadershown=1;
  8142.             }
  8143.             my $p=' ';
  8144.             if ($total_h) { $p=int($_os_h{$key}/$total_h*1000)/10; $p="$p %"; }
  8145.             print "<tr>";
  8146.             if ($key eq 'Unknown') {
  8147.                 print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/unknown.png\"".AltTitle("")." /></td><td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td>";
  8148.             }
  8149.             else {
  8150.                 my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i;
  8151.                 my $libos=$OSHashLib{$keywithoutcumul}||$keywithoutcumul;
  8152.                 my $nameicon=$keywithoutcumul; $nameicon =~ s/[^\w]//g;
  8153.                 print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/os\/$nameicon.png\"".AltTitle("")." /></td><td class=\"aws\">$libos</td>";
  8154.             }
  8155.             my $bredde_h=0;
  8156.             if ($max_h > 0) { $bredde_h=int($BarWidth*($_os_h{$key}||0)/$max_h)+1; }
  8157.             if (($bredde_h==1) && $_os_h{$key}) { $bredde_h=2; }
  8158.             print "<td>$_os_h{$key}</td><td>$p</td>";
  8159.             print "<td class=\"aws\">";
  8160.             # alt and title are not provided to reduce page size
  8161.             if ($ShowOSStats) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\" /><br />"; }
  8162.             print "</td>";
  8163.             print "</tr>\n";
  8164.         }
  8165.         &tab_end();
  8166.         &html_end(1);
  8167.     }
  8168.     if ($HTMLOutput{'browserdetail'}) {
  8169.         # Show browsers versions
  8170.         print "$Center<a name=\"browsersversions\"> </a><br />";
  8171.         my $title="$Message[21]";
  8172.         &tab_head("$title",19,0,'browsersversions');
  8173.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"2\">$Message[58]</th>";
  8174.         print "<th width=\"80\">$Message[111]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>";
  8175.         print "<th> </th>";
  8176.         print "</tr>\n";
  8177.         $total_h=0;
  8178.         my $count=0;
  8179.         &BuildKeyList(MinimumButNoZero(scalar keys %_browser_h,500),1,\%_browser_h,\%_browser_h);
  8180.         my %keysinkeylist=();
  8181.         $max_h=1;
  8182.         # Count total by family
  8183.         my %totalfamily_h=();
  8184.         my $TotalFamily=0;
  8185.         BROWSERLOOP: foreach my $key (@keylist) {
  8186.             $total_h+=$_browser_h{$key};
  8187.             if ($_browser_h{$key} > $max_h) { $max_h = $_browser_h{$key}; }
  8188.             foreach my $family (keys %BrowsersFamily) { if ($key =~ /^$family/i) { $totalfamily_h{$family}+=$_browser_h{$key}; $TotalFamily+=$_browser_h{$key}; next BROWSERLOOP; } }
  8189.         }
  8190.         # Write records grouped in a browser family
  8191.         foreach my $family (sort { $BrowsersFamily{$a} <=> $BrowsersFamily{$b} } keys %BrowsersFamily) {
  8192.             my $p=' ';
  8193.             if ($total_h) { $p=int($totalfamily_h{$family}/$total_h*1000)/10; $p="$p %"; }
  8194.             my $familyheadershown=0;
  8195.             foreach my $key (reverse sort keys %_browser_h) {
  8196.                 if ($key =~ /^$family(.*)/i) {
  8197.                     if (! $familyheadershown) {
  8198.                         print "<tr bgcolor=\"#F6F6F6\"><td class=\"aws\" colspan=\"2\"><b>".uc($family)."</b></td>";
  8199.                         print "<td> </td><td><b>".int($totalfamily_h{$family})."</b></td><td><b>$p</b></td><td> </td>";
  8200.                         print "</tr>\n";
  8201.                         $familyheadershown=1;
  8202.                     }
  8203.                     $keysinkeylist{$key}=1;
  8204.                     my $ver=$1;
  8205.                     my $p=' ';
  8206.                     if ($total_h) { $p=int($_browser_h{$key}/$total_h*1000)/10; $p="$p %"; }
  8207.                     print "<tr>";
  8208.                     print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/$family.png\"".AltTitle("")." /></td>";
  8209.                     print "<td class=\"aws\">".ucfirst($family)." ".($ver?"$ver":"?")."</td>";
  8210.                     print "<td>".($BrowsersHereAreGrabbers{$family}?"<b>$Message[112]</b>":"$Message[113]")."</td>";
  8211.                     my $bredde_h=0;
  8212.                     if ($max_h > 0) { $bredde_h=int($BarWidth*($_browser_h{$key}||0)/$max_h)+1; }
  8213.                     if (($bredde_h==1) && $_browser_h{$key}) { $bredde_h=2; }
  8214.                     print "<td>$_browser_h{$key}</td><td>$p</td>";
  8215.                     print "<td class=\"aws\">";
  8216.                     # alt and title are not provided to reduce page size
  8217.                     if ($ShowBrowsersStats) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\" /><br />"; }
  8218.                     print "</td>";
  8219.                     print "</tr>\n";
  8220.                     $count++;
  8221.                 }
  8222.             }
  8223.         }
  8224.         # Write other records
  8225.         my $familyheadershown=0;
  8226.         foreach my $key (@keylist) {
  8227.             if ($keysinkeylist{$key}) { next; }
  8228.             if (! $familyheadershown) {
  8229.                 my $p=' ';
  8230.                 if ($total_h) { $p=int(($total_h-$TotalFamily)/$total_h*1000)/10; $p="$p %"; }
  8231.                 print "<tr bgcolor=\"#F6F6F6\"><td class=\"aws\" colspan=\"2\"><b>".uc($Message[2])."</b></td>";
  8232.                 print "<td> </td><td><b>".($total_h-$TotalFamily)."</b></td><td><b>$p</b></td><td> </td>";
  8233.                 print "</tr>\n";
  8234.                 $familyheadershown=1;
  8235.             }
  8236.             my $p=' ';
  8237.             if ($total_h) { $p=int($_browser_h{$key}/$total_h*1000)/10; $p="$p %"; }
  8238.             print "<tr>";
  8239.             if ($key eq 'Unknown') {
  8240.                 print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/unknown.png\"".AltTitle("")." /></td><td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td><td width=\"80\">?</td>";
  8241.             }
  8242.             else {
  8243.                 my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i;
  8244.                 my $libbrowser=$BrowsersHashIDLib{$keywithoutcumul}||$keywithoutcumul;
  8245.                 my $nameicon=$BrowsersHashIcon{$keywithoutcumul}||"notavailable";
  8246.                 print "<td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/$nameicon.png\"".AltTitle("")." /></td><td class=\"aws\">$libbrowser</td><td>".($BrowsersHereAreGrabbers{$key}?"<b>$Message[112]</b>":"$Message[113]")."</td>";
  8247.             }
  8248.             my $bredde_h=0;
  8249.             if ($max_h > 0) { $bredde_h=int($BarWidth*($_browser_h{$key}||0)/$max_h)+1; }
  8250.             if (($bredde_h==1) && $_browser_h{$key}) { $bredde_h=2; }
  8251.             print "<td>$_browser_h{$key}</td><td>$p</td>";
  8252.             print "<td class=\"aws\">";
  8253.             # alt and title are not provided to reduce page size
  8254.             if ($ShowBrowsersStats) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\" /><br />"; }
  8255.             print "</td>";
  8256.             print "</tr>\n";
  8257.         }
  8258.         &tab_end();
  8259.         &html_end(1);
  8260.     }
  8261.     if ($HTMLOutput{'refererse'}) {
  8262.         print "$Center<a name=\"refererse\"> </a><br />\n";
  8263.         my $title="$Message[40]";
  8264.         &tab_head("$title",19,0,'refererse');
  8265.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$TotalDifferentSearchEngines $Message[122]</th>";
  8266.         print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th><th bgcolor=\"#$color_p\" width=\"80\">$Message[15]</th>";
  8267.         print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>";
  8268.         print "</tr>\n";
  8269.         $total_s=0;
  8270.         my $count=0;
  8271.         &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Refer'},\%_se_referrals_h,((scalar keys %_se_referrals_p)?\%_se_referrals_p:\%_se_referrals_h));    # before 5.4 only hits were recorded
  8272.         foreach my $key (@keylist) {
  8273.             my $newreferer=CleanFromCSSA($SearchEnginesHashLib{$key}||$key);
  8274.             my $p_p; my $p_h;
  8275.             if ($TotalSearchEnginesPages) { $p_p=int($_se_referrals_p{$key}/$TotalSearchEnginesPages*1000)/10; }
  8276.             if ($TotalSearchEnginesHits) { $p_h=int($_se_referrals_h{$key}/$TotalSearchEnginesHits*1000)/10; }
  8277.             print "<tr><td class=\"aws\">$newreferer</td>";
  8278.             print "<td>".($_se_referrals_p{$key}?$_se_referrals_p{$key}:' ')."</td>";
  8279.             print "<td>".($_se_referrals_p{$key}?"$p_p %":' ')."</td>";
  8280.             print "<td>$_se_referrals_h{$key}</td>";
  8281.             print "<td>$p_h %</td>";
  8282.             print "</tr>\n";
  8283.             $total_p += $_se_referrals_p{$key};
  8284.             $total_h += $_se_referrals_h{$key};
  8285.             $count++;
  8286.         }
  8287.         if ($Debug) { debug("Total real / shown : $TotalSearchEnginesPages / $total_p - $TotalSearchEnginesHits / $total_h",2); }
  8288.         $rest_p=$TotalSearchEnginesPages-$total_p;
  8289.         $rest_h=$TotalSearchEnginesHits-$total_h;
  8290.         if ($rest_p > 0 || $rest_h > 0) {
  8291.             my $p_p;my $p_h;
  8292.             if ($TotalSearchEnginesPages) { $p_p=int($rest_p/$TotalSearchEnginesPages*1000)/10; }
  8293.             if ($TotalSearchEnginesHits) { $p_h=int($rest_h/$TotalSearchEnginesHits*1000)/10; }
  8294.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  8295.             print "<td>".($rest_p?$rest_p:' ')."</td>";
  8296.             print "<td>".($rest_p?"$p_p %":' ')."</td>";
  8297.             print "<td>$rest_h</td>";
  8298.             print "<td>$p_h %</td>";
  8299.             print "</tr>\n";
  8300.         }
  8301.         &tab_end();
  8302.         &html_end(1);
  8303.     }
  8304.     if ($HTMLOutput{'refererpages'}) {
  8305.         print "$Center<a name=\"refererpages\"> </a><br />\n";
  8306.         # Show filter form
  8307.         &ShowFormFilter("refererpagesfilter",$FilterIn{'refererpages'},$FilterEx{'refererpages'});
  8308.         my $title="$Message[41]"; my $cpt=0;
  8309.         $cpt=(scalar keys %_pagesrefs_h);
  8310.         &tab_head("$title",19,0,'refererpages');
  8311.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>";
  8312.         if ($FilterIn{'refererpages'} || $FilterEx{'refererpages'}) {
  8313.             if ($FilterIn{'refererpages'}) { print "$Message[79] <b>$FilterIn{'refererpages'}</b>"; }
  8314.             if ($FilterIn{'refererpages'} && $FilterEx{'refererpages'}) { print " - "; }
  8315.             if ($FilterEx{'refererpages'}) { print "Exclude $Message[79] <b>$FilterEx{'refererpages'}</b>"; }
  8316.             if ($FilterIn{'refererpages'} || $FilterEx{'refererpages'}) { print ": "; }
  8317.             print "$cpt $Message[28]";
  8318.             #if ($MonthRequired ne 'all') {
  8319.             #    if ($HTMLOutput{'refererpages'}) { print "<br />$Message[102]: $TotalDifferentPages $Message[28]"; }
  8320.             #}
  8321.         }
  8322.         else { print "$Message[102]: $cpt $Message[28]"; }
  8323.         print "</th>";
  8324.         print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th><th bgcolor=\"#$color_p\" width=\"80\">$Message[15]</th>";
  8325.         print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>";
  8326.         print "</tr>\n";
  8327.         $total_s=0;
  8328.         my $count=0;
  8329.         &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Refer'},\%_pagesrefs_h,((scalar keys %_pagesrefs_p)?\%_pagesrefs_p:\%_pagesrefs_h));
  8330.         foreach my $key (@keylist) {
  8331.             my $nompage=CleanFromCSSA($key);
  8332.             if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; }
  8333.             my $p_p; my $p_h;
  8334.             if ($TotalRefererPages) { $p_p=int($_pagesrefs_p{$key}/$TotalRefererPages*1000)/10; }
  8335.             if ($TotalRefererHits) { $p_h=int($_pagesrefs_h{$key}/$TotalRefererHits*1000)/10; }
  8336.             print "<tr><td class=\"aws\">";
  8337.             &ShowURLInfo($key);
  8338.             print "</td>";
  8339.             print "<td>".($_pagesrefs_p{$key}?$_pagesrefs_p{$key}:' ')."</td><td>".($_pagesrefs_p{$key}?"$p_p %":' ')."</td>";
  8340.             print "<td>".($_pagesrefs_h{$key}?$_pagesrefs_h{$key}:' ')."</td><td>".($_pagesrefs_h{$key}?"$p_h %":' ')."</td>";
  8341.             print "</tr>\n";
  8342.             $total_p += $_pagesrefs_p{$key};
  8343.             $total_h += $_pagesrefs_h{$key};
  8344.             $count++;
  8345.         }
  8346.         if ($Debug) { debug("Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",2); }
  8347.         $rest_p=$TotalRefererPages-$total_p;
  8348.         $rest_h=$TotalRefererHits-$total_h;
  8349.         if ($rest_p > 0 || $rest_h > 0) {
  8350.             my $p_p; my $p_h;
  8351.             if ($TotalRefererPages) { $p_p=int($rest_p/$TotalRefererPages*1000)/10; }
  8352.             if ($TotalRefererHits) { $p_h=int($rest_h/$TotalRefererHits*1000)/10; }
  8353.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  8354.             print "<td>".($rest_p?$rest_p:' ')."</td>";
  8355.             print "<td>".($rest_p?"$p_p %":' ')."</td>";
  8356.             print "<td>$rest_h</td>";
  8357.             print "<td>$p_h %</td>";
  8358.             print "</tr>\n";
  8359.         }
  8360.         &tab_end();
  8361.         &html_end(1);
  8362.     }
  8363.     if ($HTMLOutput{'keyphrases'}) {
  8364.         print "$Center<a name=\"keyphrases\"> </a><br />\n";
  8365.         &tab_head($Message[43],19,0,'keyphrases');
  8366.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(15)."><th>$TotalDifferentKeyphrases $Message[103]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[14]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[15]</th></tr>\n";
  8367.         $total_s=0;
  8368.         my $count=0;
  8369.         &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Keyphrase'},\%_keyphrases,\%_keyphrases);
  8370.         foreach my $key (@keylist) {
  8371.             my $mot;
  8372.             # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
  8373.             if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'})  { $mot=CleanFromCSSA(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); }
  8374.             else { $mot = CleanFromCSSA(DecodeEncodedString($key)); }
  8375.             my $p;
  8376.             if ($TotalKeyphrases) { $p=int($_keyphrases{$key}/$TotalKeyphrases*1000)/10; }
  8377.             print "<tr><td class=\"aws\">".XMLEncode($mot)."</td><td>$_keyphrases{$key}</td><td>$p %</td></tr>\n";
  8378.             $total_s += $_keyphrases{$key};
  8379.             $count++;
  8380.         }
  8381.         if ($Debug) { debug("Total real / shown : $TotalKeyphrases / $total_s",2); }
  8382.         $rest_s=$TotalKeyphrases-$total_s;
  8383.         if ($rest_s > 0) {
  8384.             my $p;
  8385.             if ($TotalKeyphrases) { $p=int($rest_s/$TotalKeyphrases*1000)/10; }
  8386.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[124]</span></td><td>$rest_s</td>";
  8387.             print "<td>$p %</td></tr>\n";
  8388.         }
  8389.         &tab_end();
  8390.         &html_end(1);
  8391.     }
  8392.     if ($HTMLOutput{'keywords'}) {
  8393.         print "$Center<a name=\"keywords\"> </a><br />\n";
  8394.         &tab_head($Message[44],19,0,'keywords');
  8395.         print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(15)."><th>$TotalDifferentKeywords $Message[13]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[14]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[15]</th></tr>\n";
  8396.         $total_s=0;
  8397.         my $count=0;
  8398.         &BuildKeyList($MaxRowsInHTMLOutput,$MinHit{'Keyword'},\%_keywords,\%_keywords);
  8399.         foreach my $key (@keylist) {
  8400.             my $mot;
  8401.             # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
  8402.             if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'})  { $mot=CleanFromCSSA(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); }
  8403.             else { $mot = CleanFromCSSA(DecodeEncodedString($key)); }
  8404.             my $p;
  8405.             if ($TotalKeywords) { $p=int($_keywords{$key}/$TotalKeywords*1000)/10; }
  8406.             print "<tr><td class=\"aws\">".XMLEncode($mot)."</td><td>$_keywords{$key}</td><td>$p %</td></tr>\n";
  8407.             $total_s += $_keywords{$key};
  8408.             $count++;
  8409.         }
  8410.         if ($Debug) { debug("Total real / shown : $TotalKeywords / $total_s",2); }
  8411.         $rest_s=$TotalKeywords-$total_s;
  8412.         if ($rest_s > 0) {
  8413.             my $p;
  8414.             if ($TotalKeywords) { $p=int($rest_s/$TotalKeywords*1000)/10; }
  8415.             print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[30]</span></td><td>$rest_s</td>";
  8416.             print "<td>$p %</td></tr>\n";
  8417.         }
  8418.         &tab_end();
  8419.         &html_end(1);
  8420.     }
  8421.     foreach my $code (keys %TrapInfosForHTTPErrorCodes) {
  8422.         if ($HTMLOutput{"errors$code"}) {
  8423.             print "$Center<a name=\"errors$code\"> </a><br />\n";
  8424.             &tab_head($Message[47],19,0,"errors$code");
  8425.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>URL (".(scalar keys %_sider404_h).")</th><th bgcolor=\"#$color_h\">$Message[49]</th><th>$Message[23]</th></tr>\n";
  8426.             $total_h=0;
  8427.             my $count=0;
  8428.             &BuildKeyList($MaxRowsInHTMLOutput,1,\%_sider404_h,\%_sider404_h);
  8429.             foreach my $key (@keylist) {
  8430.                 my $nompage=XMLEncode(CleanFromCSSA($key));
  8431.                 #if (length($nompage)>$MaxLengthOfShownURL) { $nompage=substr($nompage,0,$MaxLengthOfShownURL)."..."; }
  8432.                 my $referer=XMLEncode(CleanFromCSSA($_referer404_h{$key}));
  8433.                 print "<tr><td class=\"aws\">$nompage</td>";
  8434.                 print "<td>$_sider404_h{$key}</td>";
  8435.                 print "<td class=\"aws\">".($referer?"$referer":" ")."</td>";
  8436.                 print "</tr>\n";
  8437.                 $total_s += $_sider404_h{$key};
  8438.                 $count++;
  8439.             }
  8440.             # TODO Build TotalErrorHits
  8441. #            if ($Debug) { debug("Total real / shown : $TotalErrorHits / $total_h",2); }
  8442. #            $rest_h=$TotalErrorHits-$total_h;
  8443. #            if ($rest_h > 0) {
  8444. #                my $p;
  8445. #                if ($TotalErrorHits) { $p=int($rest_h/$TotalErrorHits*1000)/10; }
  8446. #                print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[30]</span></td>";
  8447. #                print "<td>$rest_h</td>";
  8448. #                print "<td>...</td>";
  8449. #                print "</tr>\n";
  8450. #            }
  8451.             &tab_end();
  8452.             &html_end(1);
  8453.         }
  8454.     }
  8455.     if ($HTMLOutput{'info'}) {
  8456.         # Not yet available
  8457.         print "$Center<a name=\"info\"> </a><br />";
  8458.         &html_end(1);
  8459.     }
  8460.     if ($HTMLOutput{'main'}) {
  8461.  
  8462.         # SUMMARY
  8463.         #---------------------------------------------------------------------
  8464.         if ($ShowMonthStats) {
  8465.             if ($Debug) { debug("ShowMonthStats",2); }
  8466.             my $title="$Message[128]";
  8467.             &tab_head("$title",0,0,'month');
  8468.  
  8469.             my $NewLinkParams=${QueryString};
  8470.             $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  8471.             $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  8472.             $NewLinkParams =~ s/(^|&)year=[^&]*//i;
  8473.             $NewLinkParams =~ s/(^|&)month=[^&]*//i;
  8474.             $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  8475.             $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  8476.             if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  8477.             my $NewLinkTarget='';
  8478.             if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; }
  8479.     
  8480.             # Ratio
  8481.             my $RatioVisits=0; my $RatioPages=0; my $RatioHits=0; my $RatioBytes=0;
  8482.             if ($TotalUnique > 0) { $RatioVisits=int($TotalVisits/$TotalUnique*100)/100; }
  8483.             if ($TotalVisits > 0) { $RatioPages=int($TotalPages/$TotalVisits*100)/100; }
  8484.             if ($TotalVisits > 0) { $RatioHits=int($TotalHits/$TotalVisits*100)/100; }
  8485.             if ($TotalVisits > 0) { $RatioBytes=int(($TotalBytes/1024)*100/($LogType eq 'M'?$TotalHits:$TotalVisits))/100; }
  8486.     
  8487.             my $colspan=5;
  8488.             my $w='20';
  8489.             if ($LogType eq 'W' || $LogType eq 'S') { $w='17'; $colspan=6; }
  8490.             
  8491.             # Show first/last
  8492.             print "<tr bgcolor=\"#$color_TableBGRowTitle\">";
  8493.             print "<td class=\"aws\"><b>$Message[133]</b></td><td class=\"aws\" colspan=\"".($colspan-1)."\">\n";
  8494.             print ($MonthRequired eq 'all'?"$Message[6] $YearRequired":"$Message[5] ".$MonthNumLib{$MonthRequired}." $YearRequired");
  8495.             print "</td></tr>\n";
  8496.             print "<tr bgcolor=\"#$color_TableBGRowTitle\">";
  8497.             print "<td class=\"aws\"><b>$Message[8]</b></td>\n";
  8498.             print "<td class=\"aws\" colspan=\"".($colspan-1)."\">".($FirstTime?Format_Date($FirstTime,0):"NA")."</td>";
  8499.             print "</tr>\n";
  8500.             print "<tr bgcolor=\"#$color_TableBGRowTitle\">";
  8501.             print "<td class=\"aws\"><b>$Message[9]</b></td>\n";
  8502.             print "<td class=\"aws\" colspan=\"".($colspan-1)."\">".($LastTime?Format_Date($LastTime,0):"NA")."</td>\n";
  8503.             print "</tr>\n";
  8504.             
  8505.             # Show main indicators title row
  8506.             print "<tr>";
  8507.             if ($LogType eq 'W' || $LogType eq 'S') { print "<td bgcolor=\"#$color_TableBGTitle\"> </td>"; }
  8508.             if ($ShowMonthStats =~ /U/i) { print "<td width=\"$w%\" bgcolor=\"#$color_u\"".Tooltip(2).">$Message[11]</td>"; } else { print "<td bgcolor=\"#$color_TableBGTitle\" width=\"20%\"> </td>"; }
  8509.             if ($ShowMonthStats =~ /V/i) { print "<td width=\"$w%\" bgcolor=\"#$color_v\"".Tooltip(1).">$Message[10]</td>"; } else { print "<td bgcolor=\"#$color_TableBGTitle\" width=\"20%\"> </td>"; }
  8510.             if ($ShowMonthStats =~ /P/i) { print "<td width=\"$w%\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; } else { print "<td bgcolor=\"#$color_TableBGTitle\" width=\"20%\"> </td>"; }
  8511.             if ($ShowMonthStats =~ /H/i) { print "<td width=\"$w%\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; } else { print "<td bgcolor=\"#$color_TableBGTitle\" width=\"20%\"> </td>"; }
  8512.             if ($ShowMonthStats =~ /B/i) { print "<td width=\"$w%\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; } else { print "<td bgcolor=\"#$color_TableBGTitle\" width=\"20%\"> </td>"; }
  8513.             print "</tr>\n";
  8514.             # Show main indicators values for viewed traffic
  8515.             print "<tr>";
  8516.             if ($LogType eq 'M') { 
  8517.                 print "<td class=\"aws\">$Message[165]</td>";
  8518.                 print "<td> <br /> </td>\n";
  8519.                 print "<td> <br /> </td>\n";
  8520.                 if ($ShowMonthStats =~ /H/i) { print "<td><b>$TotalHits</b>".($LogType eq 'M'?"":"<br />($RatioHits ".lc($Message[57]."/".$Message[12]).")</td>"); } else { print "<td> </td>"; }
  8521.                 if ($ShowMonthStats =~ /B/i) { print "<td><b>".Format_Bytes(int($TotalBytes))."</b><br />($RatioBytes $Message[108]/".lc($Message[($LogType eq 'M'?149:12)]).")</td>"; } else { print "<td> </td>"; }
  8522.             }
  8523.             else {
  8524.                 if ($LogType eq 'W' || $LogType eq 'S') { print "<td class=\"aws\">$Message[160] *</td>"; }
  8525.                 if ($ShowMonthStats =~ /U/i) { print "<td>".($MonthRequired eq 'all'?"<b><= $TotalUnique</b><br />$Message[129]":"<b>$TotalUnique</b><br /> ")."</td>"; } else { print "<td> </td>"; }
  8526.                 if ($ShowMonthStats =~ /V/i) { print "<td><b>$TotalVisits</b><br />($RatioVisits $Message[52])</td>"; } else { print "<td> </td>"; }
  8527.                 if ($ShowMonthStats =~ /P/i) { print "<td><b>$TotalPages</b><br />($RatioPages ".lc($Message[56]."/".$Message[12]).")</td>"; } else { print "<td> </td>"; }
  8528.                 if ($ShowMonthStats =~ /H/i) { print "<td><b>$TotalHits</b>".($LogType eq 'M'?"":"<br />($RatioHits ".lc($Message[57]."/".$Message[12]).")</td>"); } else { print "<td> </td>"; }
  8529.                 if ($ShowMonthStats =~ /B/i) { print "<td><b>".Format_Bytes(int($TotalBytes))."</b><br />($RatioBytes $Message[108]/".lc($Message[($LogType eq 'M'?149:12)]).")</td>"; } else { print "<td> </td>"; }
  8530.             }
  8531.             print "</tr>\n";
  8532.             # Show main indicators values for not viewed traffic values
  8533.             if ($LogType eq 'M' || $LogType eq 'W' || $LogType eq 'S') {
  8534.                 print "<tr>";
  8535.                 if ($LogType eq 'M') { 
  8536.                     print "<td class=\"aws\">$Message[166]</td>";
  8537.                     print "<td> <br /> </td>\n";
  8538.                     print "<td> <br /> </td>\n";
  8539.                     if ($ShowMonthStats =~ /H/i) { print "<td><b>$TotalNotViewedHits</b></td>"; } else { print "<td> </td>"; }
  8540.                     if ($ShowMonthStats =~ /B/i) { print "<td><b>".Format_Bytes(int($TotalNotViewedBytes))."</b></td>"; } else { print "<td> </td>"; }
  8541.                 }
  8542.                 else {
  8543.                     if ($LogType eq 'W' || $LogType eq 'S') { print "<td class=\"aws\">$Message[161] *</td>"; }
  8544.                     print "<td colspan=\"2\"> <br /> </td>\n";
  8545.                     if ($ShowMonthStats =~ /P/i) { print "<td><b>$TotalNotViewedPages</b></td>"; } else { print "<td> </td>"; }
  8546.                     if ($ShowMonthStats =~ /H/i) { print "<td><b>$TotalNotViewedHits</b></td>"; } else { print "<td> </td>"; }
  8547.                     if ($ShowMonthStats =~ /B/i) { print "<td><b>".Format_Bytes(int($TotalNotViewedBytes))."</b></td>"; } else { print "<td> </td>"; }
  8548.                 }
  8549.                 print "</tr>\n";
  8550.             }
  8551.             &tab_end($LogType eq 'W' || $LogType eq 'S'?"* $Message[159]":"");
  8552.  
  8553.             # BY MONTH
  8554.             #---------------------------------------------------------------------
  8555.             if ($ShowMonthStats) {
  8556.  
  8557.             if ($Debug) { debug("ShowMonthStats",2); }
  8558.             print "$Center<a name=\"month\"> </a><br />\n";
  8559.             my $title="$Message[162]";
  8560.             &tab_head("$title",0,0,'month');
  8561.             print "<tr><td align=\"center\">\n";
  8562.             print "<center>\n";
  8563.  
  8564.             $average_nb=$average_u=$average_v=$average_p=$average_h=$average_k=0;
  8565.             $total_u=$total_v=$total_p=$total_h=$total_k=0;
  8566.  
  8567.             $max_v=$max_p=$max_h=$max_k=1;
  8568.             # Define total and max
  8569.             for (my $ix=1; $ix<=12; $ix++) {
  8570.                 my $monthix=sprintf("%02s",$ix);
  8571.                 $total_u+=$MonthUnique{$YearRequired.$monthix}||0;
  8572.                 $total_v+=$MonthVisits{$YearRequired.$monthix}||0;
  8573.                 $total_p+=$MonthPages{$YearRequired.$monthix}||0;
  8574.                 $total_h+=$MonthHits{$YearRequired.$monthix}||0;
  8575.                 $total_k+=$MonthBytes{$YearRequired.$monthix}||0;
  8576.                 #if (($MonthUnique{$YearRequired.$monthix}||0) > $max_v) { $max_v=$MonthUnique{$YearRequired.$monthix}; }
  8577.                 if (($MonthVisits{$YearRequired.$monthix}||0) > $max_v) { $max_v=$MonthVisits{$YearRequired.$monthix}; }
  8578.                 #if (($MonthPages{$YearRequired.$monthix}||0) > $max_p)  { $max_p=$MonthPages{$YearRequired.$monthix}; }
  8579.                 if (($MonthHits{$YearRequired.$monthix}||0) > $max_h)   { $max_h=$MonthHits{$YearRequired.$monthix}; }
  8580.                 if (($MonthBytes{$YearRequired.$monthix}||0) > $max_k)  { $max_k=$MonthBytes{$YearRequired.$monthix}; }
  8581.             }
  8582.             # Define average
  8583.             # TODO
  8584.  
  8585.             # Show bars for month
  8586.             if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) {
  8587.                 my @blocklabel=();
  8588.                 for (my $ix=1; $ix<=12; $ix++) {
  8589.                     my $monthix=sprintf("%02s",$ix);
  8590.                     push @blocklabel,"$MonthNumLib{$monthix}º$YearRequired";
  8591.                 }
  8592.                 my @vallabel=("$Message[11]","$Message[10]","$Message[56]","$Message[57]","$Message[75]");
  8593.                 my @valcolor=("$color_u","$color_v","$color_p","$color_h","$color_k");
  8594.                 my @valmax=($max_v,$max_v,$max_h,$max_h,$max_k);
  8595.                 my @valtotal=($total_u,$total_v,$total_p,$total_h,$total_k);
  8596.                 my @valaverage=();
  8597.                 #my @valaverage=($average_v,$average_p,$average_h,$average_k);
  8598.                 my @valdata=();
  8599.                 my $xx=0;
  8600.                 for (my $ix=1; $ix<=12; $ix++) {
  8601.                     my $monthix=sprintf("%02s",$ix);
  8602.                     $valdata[$xx++]=$MonthUnique{$YearRequired.$monthix}||0;
  8603.                     $valdata[$xx++]=$MonthVisits{$YearRequired.$monthix}||0;
  8604.                     $valdata[$xx++]=$MonthPages{$YearRequired.$monthix}||0;
  8605.                     $valdata[$xx++]=$MonthHits{$YearRequired.$monthix}||0;
  8606.                     $valdata[$xx++]=$MonthBytes{$YearRequired.$monthix}||0;
  8607.                 }
  8608.                 ShowGraph_graphapplet("$title","month",$ShowMonthStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata);
  8609.             }
  8610.             else {            
  8611.                 print "<table>\n";
  8612.                 print "<tr valign=\"bottom\">";
  8613.                 print "<td> </td>\n";
  8614.                 for (my $ix=1; $ix<=12; $ix++) {
  8615.                     my $monthix=sprintf("%02s",$ix);
  8616.                     my $bredde_u=0; my $bredde_v=0;my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  8617.                     if ($max_v > 0) { $bredde_u=int(($MonthUnique{$YearRequired.$monthix}||0)/$max_v*$BarHeight)+1; }
  8618.                     if ($max_v > 0) { $bredde_v=int(($MonthVisits{$YearRequired.$monthix}||0)/$max_v*$BarHeight)+1; }
  8619.                     if ($max_h > 0) { $bredde_p=int(($MonthPages{$YearRequired.$monthix}||0)/$max_h*$BarHeight)+1; }
  8620.                     if ($max_h > 0) { $bredde_h=int(($MonthHits{$YearRequired.$monthix}||0)/$max_h*$BarHeight)+1; }
  8621.                     if ($max_k > 0) { $bredde_k=int(($MonthBytes{$YearRequired.$monthix}||0)/$max_k*$BarHeight)+1; }
  8622.                     print "<td>";
  8623.                     if ($ShowMonthStats =~ /U/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vu'}\" height=\"$bredde_u\" width=\"6\"".AltTitle("$Message[11]: ".($MonthUnique{$YearRequired.$monthix}||0))." />"; }
  8624.                     if ($ShowMonthStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"6\"".AltTitle("$Message[10]: ".($MonthVisits{$YearRequired.$monthix}||0))." />"; }
  8625.                     if ($QueryString !~ /buildpdf/i) { print " "; }
  8626.                     if ($ShowMonthStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"6\"".AltTitle("$Message[56]: ".($MonthPages{$YearRequired.$monthix}||0))." />"; }
  8627.                     if ($ShowMonthStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"6\"".AltTitle("$Message[57]: ".($MonthHits{$YearRequired.$monthix}||0))." />"; }
  8628.                     if ($ShowMonthStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"6\"".AltTitle("$Message[75]: ".Format_Bytes($MonthBytes{$YearRequired.$monthix}))." />"; }
  8629.                     print "</td>\n";
  8630.                 }
  8631.                 print "<td> </td>";
  8632.                 print "</tr>\n";
  8633.                 # Show lib for month
  8634.                 print "<tr valign=\"middle\">";
  8635. #                if ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) {
  8636. #                    print "<td><a href=\"".XMLEncode("$AWScript?${NewLinkParams}month=12&year=".($YearRequired-1))."\"><<</a></td>";
  8637. #                }
  8638. #                else {
  8639.                     print "<td> </td>";
  8640. #                }
  8641.                 for (my $ix=1; $ix<=12; $ix++) {
  8642.                     my $monthix=sprintf("%02s",$ix);
  8643. #                    if ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) {
  8644. #                        print "<td><a href=\"".XMLEncode("$AWScript?${NewLinkParams}month=$monthix&year=$YearRequired")."\">$MonthNumLib{$monthix}<br />$YearRequired</a></td>";
  8645. #                    }
  8646. #                    else {
  8647.                         print "<td>$MonthNumLib{$monthix}<br />$YearRequired</td>";
  8648. #                    }
  8649.                 }
  8650. #                if ($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks) {
  8651. #                    print "<td><a href=\"".XMLEncode("$AWScript?${NewLinkParams}month=1&year=".($YearRequired+1))."\">>></a></td>";
  8652. #                }
  8653. #                else {
  8654.                     print "<td> </td>";
  8655. #                }
  8656.                 print "</tr>\n";
  8657.                 print "</table>\n";
  8658.             }
  8659.             print "<br />\n";
  8660.  
  8661.             # Show data array for month
  8662.             if ($AddDataArrayMonthStats) {
  8663.                 print "<table>\n";
  8664.                 print "<tr><td width=\"80\" bgcolor=\"#$color_TableBGRowTitle\">$Message[5]</td>";
  8665.                 if ($ShowMonthStats =~ /U/i) { print "<td width=\"80\" bgcolor=\"#$color_u\"".Tooltip(2).">$Message[11]</td>"; }
  8666.                 if ($ShowMonthStats =~ /V/i) { print "<td width=\"80\" bgcolor=\"#$color_v\"".Tooltip(1).">$Message[10]</td>"; }
  8667.                 if ($ShowMonthStats =~ /P/i) { print "<td width=\"80\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  8668.                 if ($ShowMonthStats =~ /H/i) { print "<td width=\"80\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  8669.                 if ($ShowMonthStats =~ /B/i) { print "<td width=\"80\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; }
  8670.                 print "</tr>\n";
  8671.                 for (my $ix=1; $ix<=12; $ix++) {
  8672.                     my $monthix=sprintf("%02s",$ix);
  8673.                     print "<tr>";
  8674.                     print "<td>$MonthNumLib{$monthix} $YearRequired</td>";
  8675.                     if ($ShowMonthStats =~ /U/i) { print "<td>",$MonthUnique{$YearRequired.$monthix}?$MonthUnique{$YearRequired.$monthix}:"0","</td>"; }
  8676.                     if ($ShowMonthStats =~ /V/i) { print "<td>",$MonthVisits{$YearRequired.$monthix}?$MonthVisits{$YearRequired.$monthix}:"0","</td>"; }
  8677.                     if ($ShowMonthStats =~ /P/i) { print "<td>",$MonthPages{$YearRequired.$monthix}?$MonthPages{$YearRequired.$monthix}:"0","</td>"; }
  8678.                     if ($ShowMonthStats =~ /H/i) { print "<td>",$MonthHits{$YearRequired.$monthix}?$MonthHits{$YearRequired.$monthix}:"0","</td>"; }
  8679.                     if ($ShowMonthStats =~ /B/i) { print "<td>",Format_Bytes(int($MonthBytes{$YearRequired.$monthix}||0)),"</td>"; }
  8680.                     print "</tr>\n";
  8681.                 }
  8682.                 # Average row
  8683.                 # TODO
  8684.                 # Total row
  8685.                 print "<tr><td bgcolor=\"#$color_TableBGRowTitle\">$Message[102]</td>";
  8686.                 if ($ShowMonthStats =~ /U/i) { print "<td bgcolor=\"#$color_TableBGRowTitle\">$total_u</td>"; }
  8687.                 if ($ShowMonthStats =~ /V/i) { print "<td bgcolor=\"#$color_TableBGRowTitle\">$total_v</td>"; }
  8688.                 if ($ShowMonthStats =~ /P/i) { print "<td bgcolor=\"#$color_TableBGRowTitle\">$total_p</td>"; }
  8689.                 if ($ShowMonthStats =~ /H/i) { print "<td bgcolor=\"#$color_TableBGRowTitle\">$total_h</td>"; }
  8690.                 if ($ShowMonthStats =~ /B/i) { print "<td bgcolor=\"#$color_TableBGRowTitle\">".Format_Bytes($total_k)."</td>"; }
  8691.                 print "</tr>\n";        
  8692.                 print "</table>\n<br />\n";
  8693.             }
  8694.                 
  8695.             print "</center>\n";
  8696.             print "</td></tr>\n";
  8697.             &tab_end();
  8698.         }
  8699.         }
  8700.  
  8701.         print "\n<a name=\"when\"> </a>\n\n";
  8702.  
  8703.         # BY DAY OF MONTH
  8704.         #---------------------------------------------------------------------
  8705.         if ($ShowDaysOfMonthStats) {
  8706.             if ($Debug) { debug("ShowDaysOfMonthStats",2); }
  8707.             print "$Center<a name=\"daysofmonth\"> </a><br />\n";
  8708.             my $title="$Message[138]";
  8709.             &tab_head("$title",0,0,'daysofmonth');
  8710.             print "<tr>";
  8711.             print "<td align=\"center\">\n";
  8712.             print "<center>\n";
  8713.             
  8714.             my $NewLinkParams=${QueryString};
  8715.             $NewLinkParams =~ s/(^|&)update(=\w*|$)//i;
  8716.             $NewLinkParams =~ s/(^|&)staticlinks(=\w*|$)//i;
  8717.             $NewLinkParams =~ s/(^|&)year=[^&]*//i;
  8718.             $NewLinkParams =~ s/(^|&)month=[^&]*//i;
  8719.             $NewLinkParams =~ s/(^|&)framename=[^&]*//i;
  8720.             $NewLinkParams =~ tr/&/&/s; $NewLinkParams =~ s/^&//; $NewLinkParams =~ s/&$//;
  8721.             if ($NewLinkParams) { $NewLinkParams="${NewLinkParams}&"; }
  8722.             my $NewLinkTarget='';
  8723.             if ($FrameName eq 'mainright') { $NewLinkTarget=" target=\"_parent\""; }
  8724.                 
  8725.             $average_nb=$average_u=$average_v=$average_p=$average_h=$average_k=0;
  8726.             $total_u=$total_v=$total_p=$total_h=$total_k=0;
  8727.             # Define total and max
  8728.             $max_v=$max_h=$max_k=0;        # Start from 0 because can be lower than 1
  8729.             foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8730.                 $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8731.                 my $year=$1; my $month=$2; my $day=$3;
  8732.                 if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8733.                 $total_v+=$DayVisits{$year.$month.$day}||0;
  8734.                 $total_p+=$DayPages{$year.$month.$day}||0;
  8735.                 $total_h+=$DayHits{$year.$month.$day}||0;
  8736.                 $total_k+=$DayBytes{$year.$month.$day}||0;
  8737.                 if (($DayVisits{$year.$month.$day}||0) > $max_v)  { $max_v=$DayVisits{$year.$month.$day}; }
  8738.                 #if (($DayPages{$year.$month.$day}||0) > $max_p)  { $max_p=$DayPages{$year.$month.$day}; }
  8739.                 if (($DayHits{$year.$month.$day}||0) > $max_h)   { $max_h=$DayHits{$year.$month.$day}; }
  8740.                 if (($DayBytes{$year.$month.$day}||0) > $max_k)  { $max_k=$DayBytes{$year.$month.$day}; }
  8741.             }
  8742.             # Define average
  8743.             foreach my $daycursor ($firstdaytocountaverage..$lastdaytocountaverage) {
  8744.                 $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8745.                 my $year=$1; my $month=$2; my $day=$3;
  8746.                 if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8747.                 $average_nb++;                                            # Increase number of day used to count
  8748.                 $average_v+=($DayVisits{$daycursor}||0);
  8749.                 $average_p+=($DayPages{$daycursor}||0);
  8750.                 $average_h+=($DayHits{$daycursor}||0);
  8751.                 $average_k+=($DayBytes{$daycursor}||0);
  8752.             }
  8753.             if ($average_nb) {
  8754.                 $average_v=$average_v/$average_nb;
  8755.                 $average_p=$average_p/$average_nb;
  8756.                 $average_h=$average_h/$average_nb;
  8757.                 $average_k=$average_k/$average_nb;
  8758.                 if ($average_v > $max_v) { $max_v=$average_v; }
  8759.                 #if ($average_p > $max_p) { $max_p=$average_p; }
  8760.                 if ($average_h > $max_h) { $max_h=$average_h; }
  8761.                 if ($average_k > $max_k) { $max_k=$average_k; }
  8762.             }
  8763.             else {
  8764.                 $average_v="?";
  8765.                 $average_p="?";
  8766.                 $average_h="?";
  8767.                 $average_k="?";
  8768.             }
  8769.  
  8770.             # Show bars for day
  8771.             if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) {
  8772.                 my @blocklabel=();
  8773.                 foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8774.                     $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8775.                     my $year=$1; my $month=$2; my $day=$3;
  8776.                     if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8777.                     my $bold=($day==$nowday && $month==$nowmonth && $year==$nowyear?':':'');
  8778.                     my $weekend=(DayOfWeek($day,$month,$year)=~/[06]/?'!':'');
  8779.                     push @blocklabel,"$dayº$MonthNumLib{$month}$weekend$bold";
  8780.                 }
  8781.                 my @vallabel=("$Message[10]","$Message[56]","$Message[57]","$Message[75]");
  8782.                 my @valcolor=("$color_v","$color_p","$color_h","$color_k");
  8783.                 my @valmax=($max_v,$max_h,$max_h,$max_k);
  8784.                 my @valtotal=($total_v,$total_p,$total_h,$total_k);
  8785.                 $average_v=sprintf("%.2f",$average_v);
  8786.                 $average_p=sprintf("%.2f",$average_p);
  8787.                 $average_h=sprintf("%.2f",$average_h);
  8788.                 $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00");
  8789.                 my @valaverage=($average_v,$average_p,$average_h,$average_k);
  8790.                 my @valdata=();
  8791.                 my $xx=0;
  8792.                 foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8793.                     $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8794.                     my $year=$1; my $month=$2; my $day=$3;
  8795.                     if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8796.                     $valdata[$xx++]=$DayVisits{$year.$month.$day}||0;
  8797.                     $valdata[$xx++]=$DayPages{$year.$month.$day}||0;
  8798.                     $valdata[$xx++]=$DayHits{$year.$month.$day}||0;
  8799.                     $valdata[$xx++]=$DayBytes{$year.$month.$day}||0;
  8800.                 }
  8801.                 ShowGraph_graphapplet("$title","daysofmonth",$ShowDaysOfMonthStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata);
  8802.             }
  8803.             else {            
  8804.                 print "<table>\n";
  8805.                 print "<tr valign=\"bottom\">\n";
  8806.                 foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8807.                     $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8808.                     my $year=$1; my $month=$2; my $day=$3;
  8809.                     if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8810.                     my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0;
  8811.                     if ($max_v > 0) { $bredde_v=int(($DayVisits{$year.$month.$day}||0)/$max_v*$BarHeight)+1; }
  8812.                     if ($max_h > 0) { $bredde_p=int(($DayPages{$year.$month.$day}||0)/$max_h*$BarHeight)+1; }
  8813.                     if ($max_h > 0) { $bredde_h=int(($DayHits{$year.$month.$day}||0)/$max_h*$BarHeight)+1; }
  8814.                     if ($max_k > 0) { $bredde_k=int(($DayBytes{$year.$month.$day}||0)/$max_k*$BarHeight)+1; }
  8815.                     print "<td>";
  8816.                     if ($ShowDaysOfMonthStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"4\"".AltTitle("$Message[10]: ".int($DayVisits{$year.$month.$day}||0))." />"; }
  8817.                     if ($ShowDaysOfMonthStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"4\"".AltTitle("$Message[56]: ".int($DayPages{$year.$month.$day}||0))." />"; }
  8818.                     if ($ShowDaysOfMonthStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"4\"".AltTitle("$Message[57]: ".int($DayHits{$year.$month.$day}||0))." />"; }
  8819.                     if ($ShowDaysOfMonthStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"4\"".AltTitle("$Message[75]: ".Format_Bytes($DayBytes{$year.$month.$day}))." />"; }
  8820.                     print "</td>\n";
  8821.                 }
  8822.                 print "<td> </td>";
  8823.                 # Show average value cell
  8824.                 print "<td>";
  8825.                 my $bredde_v=0; my $bredde_p=0; my $bredde_h=0; my $bredde_k=0;
  8826.                 if ($max_v > 0) { $bredde_v=int($average_v/$max_v*$BarHeight)+1; }
  8827.                 if ($max_h > 0) { $bredde_p=int($average_p/$max_h*$BarHeight)+1; }
  8828.                 if ($max_h > 0) { $bredde_h=int($average_h/$max_h*$BarHeight)+1; }
  8829.                 if ($max_k > 0) { $bredde_k=int($average_k/$max_k*$BarHeight)+1; }
  8830.                 $average_v=sprintf("%.2f",$average_v);
  8831.                 $average_p=sprintf("%.2f",$average_p);
  8832.                 $average_h=sprintf("%.2f",$average_h);
  8833.                 $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00");
  8834.                 if ($ShowDaysOfMonthStats =~ /V/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vv'}\" height=\"$bredde_v\" width=\"4\"".AltTitle("$Message[10]: $average_v")." />"; }
  8835.                 if ($ShowDaysOfMonthStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"4\"".AltTitle("$Message[56]: $average_p")." />"; }
  8836.                 if ($ShowDaysOfMonthStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"4\"".AltTitle("$Message[57]: $average_h")." />"; }
  8837.                 if ($ShowDaysOfMonthStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"4\"".AltTitle("$Message[75]: $average_k")." />"; }
  8838.                 print "</td>\n";
  8839.                 print "</tr>\n";
  8840.                 # Show lib for day
  8841.                 print "<tr valign=\"middle\">";
  8842.                 foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8843.                     $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8844.                     my $year=$1; my $month=$2; my $day=$3;
  8845.                     if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8846.                     my $dayofweekcursor=DayOfWeek($day,$month,$year);
  8847.                     print "<td".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">";
  8848.                     print ($day==$nowday && $month==$nowmonth && $year==$nowyear?'<b>':'');
  8849.                     print "$day<br /><span style=\"font-size: ".($FrameName ne 'mainright' && $QueryString !~ /buildpdf/i?"9":"8")."px;\">".$MonthNumLib{$month}."</span>";
  8850.                     print ($day==$nowday && $month==$nowmonth && $year==$nowyear?'</b>':'');
  8851.                     print "</td>\n";
  8852.                 }
  8853.                 print "<td> </td>";
  8854.                 print "<td valign=\"middle\"".Tooltip(18).">$Message[96]</td>\n";
  8855.                 print "</tr>\n";
  8856.                 print "</table>\n";
  8857.             }
  8858.             print "<br />\n";
  8859.     
  8860.             # Show data array for days
  8861.             if ($AddDataArrayShowDaysOfMonthStats) {
  8862.                 print "<table>\n";
  8863.                 print "<tr><td width=\"80\" bgcolor=\"#$color_TableBGRowTitle\">$Message[4]</td>";
  8864.                 if ($ShowDaysOfMonthStats =~ /V/i) { print "<td width=\"80\" bgcolor=\"#$color_v\"".Tooltip(1).">$Message[10]</td>"; }
  8865.                 if ($ShowDaysOfMonthStats =~ /P/i) { print "<td width=\"80\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  8866.                 if ($ShowDaysOfMonthStats =~ /H/i) { print "<td width=\"80\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  8867.                 if ($ShowDaysOfMonthStats =~ /B/i) { print "<td width=\"80\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; }
  8868.                 print "</tr>";
  8869.                 foreach my $daycursor ($firstdaytoshowtime..$lastdaytoshowtime) {
  8870.                     $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8871.                     my $year=$1; my $month=$2; my $day=$3;
  8872.                     if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8873.                     my $dayofweekcursor=DayOfWeek($day,$month,$year);
  8874.                     print "<tr".($dayofweekcursor=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">";
  8875.                     print "<td>",Format_Date("$year$month$day"."000000",2),"</td>";
  8876.                     if ($ShowDaysOfMonthStats =~ /V/i) { print "<td>",$DayVisits{$year.$month.$day}?$DayVisits{$year.$month.$day}:"0","</td>"; }
  8877.                     if ($ShowDaysOfMonthStats =~ /P/i) { print "<td>",$DayPages{$year.$month.$day}?$DayPages{$year.$month.$day}:"0","</td>"; }
  8878.                     if ($ShowDaysOfMonthStats =~ /H/i) { print "<td>",$DayHits{$year.$month.$day}?$DayHits{$year.$month.$day}:"0","</td>"; }
  8879.                     if ($ShowDaysOfMonthStats =~ /B/i) { print "<td>",Format_Bytes(int($DayBytes{$year.$month.$day}||0)),"</td>"; }
  8880.                     print "</tr>\n";
  8881.                 }
  8882.                 # Average row
  8883.                 print "<tr bgcolor=\"#$color_TableBGRowTitle\"><td>$Message[96]</td>";
  8884.                 if ($ShowDaysOfMonthStats =~ /V/i) { print "<td>$average_v</td>"; }
  8885.                 if ($ShowDaysOfMonthStats =~ /P/i) { print "<td>$average_p</td>"; }
  8886.                 if ($ShowDaysOfMonthStats =~ /H/i) { print "<td>$average_h</td>"; }
  8887.                 if ($ShowDaysOfMonthStats =~ /B/i) { print "<td>$average_k</td>"; }
  8888.                 print "</tr>\n";        
  8889.                 # Total row
  8890.                 print "<tr bgcolor=\"#$color_TableBGRowTitle\"><td>$Message[102]</td>";
  8891.                 if ($ShowDaysOfMonthStats =~ /V/i) { print "<td>$total_v</td>"; }
  8892.                 if ($ShowDaysOfMonthStats =~ /P/i) { print "<td>$total_p</td>"; }
  8893.                 if ($ShowDaysOfMonthStats =~ /H/i) { print "<td>$total_h</td>"; }
  8894.                 if ($ShowDaysOfMonthStats =~ /B/i) { print "<td>".Format_Bytes($total_k)."</td>"; }
  8895.                 print "</tr>\n";        
  8896.                 print "</table>\n<br />";
  8897.             }
  8898.                 
  8899.             print "</center>\n";
  8900.             print "</td></tr>\n";
  8901.             &tab_end();
  8902.         }
  8903.  
  8904.         # BY DAY OF WEEK
  8905.         #-------------------------
  8906.         if ($ShowDaysOfWeekStats) {
  8907.             if ($Debug) { debug("ShowDaysOfWeekStats",2); }
  8908.             print "$Center<a name=\"daysofweek\"> </a><br />\n";
  8909.             my $title="$Message[91]";
  8910.             &tab_head("$title",18,0,'daysofweek');
  8911.             print "<tr>";
  8912.             print "<td align=\"center\">";
  8913.             print "<center>\n";
  8914.  
  8915.             $max_h=$max_k=0;    # Start from 0 because can be lower than 1
  8916.             # Get average value for day of week
  8917.             my @avg_dayofweek_nb=(); my @avg_dayofweek_p=(); my @avg_dayofweek_h=(); my @avg_dayofweek_k=();
  8918.             foreach my $daycursor ($firstdaytocountaverage..$lastdaytocountaverage) {
  8919.                 $daycursor =~ /^(\d\d\d\d)(\d\d)(\d\d)/;
  8920.                 my $year=$1; my $month=$2; my $day=$3;
  8921.                 if (! DateIsValid($day,$month,$year)) { next; }            # If not an existing day, go to next
  8922.                 my $dayofweekcursor=DayOfWeek($day,$month,$year);
  8923.                 $avg_dayofweek_nb[$dayofweekcursor]++;                    # Increase number of day used to count for this day of week
  8924.                 $avg_dayofweek_p[$dayofweekcursor]+=($DayPages{$daycursor}||0);
  8925.                 $avg_dayofweek_h[$dayofweekcursor]+=($DayHits{$daycursor}||0);
  8926.                 $avg_dayofweek_k[$dayofweekcursor]+=($DayBytes{$daycursor}||0);
  8927.             }
  8928.             for (@DOWIndex) {
  8929.                 if ($avg_dayofweek_nb[$_]) {
  8930.                     $avg_dayofweek_p[$_]=$avg_dayofweek_p[$_]/$avg_dayofweek_nb[$_];
  8931.                     $avg_dayofweek_h[$_]=$avg_dayofweek_h[$_]/$avg_dayofweek_nb[$_];
  8932.                     $avg_dayofweek_k[$_]=$avg_dayofweek_k[$_]/$avg_dayofweek_nb[$_];
  8933.                     #if ($avg_dayofweek_p[$_] > $max_p) { $max_p = $avg_dayofweek_p[$_]; }
  8934.                     if ($avg_dayofweek_h[$_] > $max_h) { $max_h = $avg_dayofweek_h[$_]; }
  8935.                     if ($avg_dayofweek_k[$_] > $max_k) { $max_k = $avg_dayofweek_k[$_]; }
  8936.                 }
  8937.                 else {
  8938.                     $avg_dayofweek_p[$_]="?";
  8939.                     $avg_dayofweek_h[$_]="?";
  8940.                     $avg_dayofweek_k[$_]="?";
  8941.                 }
  8942.             }
  8943.  
  8944.             # Show bars for days of week
  8945.             if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) {
  8946.                 my @blocklabel=();
  8947.                 for (@DOWIndex) { push @blocklabel,($Message[$_+84].($_=~/[06]/?"!":"")); }
  8948.                 my @vallabel=("$Message[56]","$Message[57]","$Message[75]");
  8949.                 my @valcolor=("$color_p","$color_h","$color_k");
  8950.                 my @valmax=(int($max_h),int($max_h),int($max_k));
  8951.                 my @valtotal=($total_p,$total_h,$total_k);
  8952.                 $average_p=sprintf("%.2f",$average_p);
  8953.                 $average_h=sprintf("%.2f",$average_h);
  8954.                 $average_k=(int($average_k)?Format_Bytes(sprintf("%.2f",$average_k)):"0.00");
  8955.                 my @valaverage=($average_p,$average_h,$average_k);
  8956.                 my @valdata=();
  8957.                 my $xx=0;
  8958.                 for (@DOWIndex) {
  8959.                     $valdata[$xx++]=$avg_dayofweek_p[$_]||0;
  8960.                     $valdata[$xx++]=$avg_dayofweek_h[$_]||0;
  8961.                     $valdata[$xx++]=$avg_dayofweek_k[$_]||0;
  8962.                     # Round to be ready to show array
  8963.                     $avg_dayofweek_p[$_]=sprintf("%.2f",$avg_dayofweek_p[$_]);
  8964.                     $avg_dayofweek_h[$_]=sprintf("%.2f",$avg_dayofweek_h[$_]);
  8965.                     $avg_dayofweek_k[$_]=sprintf("%.2f",$avg_dayofweek_k[$_]);
  8966.                     # Remove decimal part that are .0
  8967.                     if ($avg_dayofweek_p[$_] == int($avg_dayofweek_p[$_])) { $avg_dayofweek_p[$_]=int($avg_dayofweek_p[$_]); }
  8968.                     if ($avg_dayofweek_h[$_] == int($avg_dayofweek_h[$_])) { $avg_dayofweek_h[$_]=int($avg_dayofweek_h[$_]); }
  8969.                 }
  8970.                 ShowGraph_graphapplet("$title","daysofweek",$ShowDaysOfWeekStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata);
  8971.             }
  8972.             else {            
  8973.                 print "<table>\n";
  8974.                 print "<tr valign=\"bottom\">\n";
  8975.                 for (@DOWIndex) {
  8976.                     my $bredde_p=0; my $bredde_h=0; my $bredde_k=0;
  8977.                     if ($max_h > 0) { $bredde_p=int($avg_dayofweek_p[$_]/$max_h*$BarHeight)+1; }
  8978.                     if ($max_h > 0) { $bredde_h=int($avg_dayofweek_h[$_]/$max_h*$BarHeight)+1; }
  8979.                     if ($max_k > 0) { $bredde_k=int($avg_dayofweek_k[$_]/$max_k*$BarHeight)+1; }
  8980.                     $avg_dayofweek_p[$_]=sprintf("%.2f",$avg_dayofweek_p[$_]);
  8981.                     $avg_dayofweek_h[$_]=sprintf("%.2f",$avg_dayofweek_h[$_]);
  8982.                     $avg_dayofweek_k[$_]=sprintf("%.2f",$avg_dayofweek_k[$_]);
  8983.                     # Remove decimal part that are .0
  8984.                     if ($avg_dayofweek_p[$_] == int($avg_dayofweek_p[$_])) { $avg_dayofweek_p[$_]=int($avg_dayofweek_p[$_]); }
  8985.                     if ($avg_dayofweek_h[$_] == int($avg_dayofweek_h[$_])) { $avg_dayofweek_h[$_]=int($avg_dayofweek_h[$_]); }
  8986.                     print "<td valign=\"bottom\">";
  8987.                     if ($ShowDaysOfWeekStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"6\"".AltTitle("$Message[56]: $avg_dayofweek_p[$_]")." />"; }
  8988.                     if ($ShowDaysOfWeekStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"6\"".AltTitle("$Message[57]: $avg_dayofweek_h[$_]")." />"; }
  8989.                     if ($ShowDaysOfWeekStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"6\"".AltTitle("$Message[75]: ".Format_Bytes($avg_dayofweek_k[$_]))." />"; }
  8990.                     print "</td>\n";
  8991.                 }
  8992.                 print "</tr>\n";
  8993.                 print "<tr".Tooltip(17).">\n";
  8994.                 for (@DOWIndex) {
  8995.                     print "<td".($_=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">".$Message[$_+84]."</td>";
  8996.                 }
  8997.                 print "</tr>\n</table>\n";
  8998.             }
  8999.             print "<br />\n";
  9000.             
  9001.             # Show data array for days of week
  9002.             if ($AddDataArrayShowDaysOfWeekStats) {
  9003.                 print "<table>\n";
  9004.                 print "<tr><td width=\"80\" bgcolor=\"#$color_TableBGRowTitle\">$Message[4]</td>";
  9005.                 if ($ShowDaysOfWeekStats =~ /P/i) { print "<td width=\"80\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  9006.                 if ($ShowDaysOfWeekStats =~ /H/i) { print "<td width=\"80\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  9007.                 if ($ShowDaysOfWeekStats =~ /B/i) { print "<td width=\"80\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td></tr>"; }
  9008.                 for (@DOWIndex) {
  9009.                     print "<tr".($_=~/[06]/?" bgcolor=\"#$color_weekend\"":"").">";
  9010.                     print "<td>".$Message[$_+84]."</td>";
  9011.                     if ($ShowDaysOfWeekStats =~ /P/i) { print "<td>",$avg_dayofweek_p[$_],"</td>"; }
  9012.                     if ($ShowDaysOfWeekStats =~ /H/i) { print "<td>",$avg_dayofweek_h[$_],"</td>"; }
  9013.                     if ($ShowDaysOfWeekStats =~ /B/i) { print "<td>",Format_Bytes($avg_dayofweek_k[$_]),"</td>"; }
  9014.                     print "</tr>\n";
  9015.                 }
  9016.                 print "</table>\n<br />\n";
  9017.             }
  9018.                         
  9019.             print "</center></td>";
  9020.             print "</tr>\n";
  9021.             &tab_end();
  9022.         }
  9023.     
  9024.         # BY HOUR
  9025.         #----------------------------
  9026.         if ($ShowHoursStats) {
  9027.             if ($Debug) { debug("ShowHoursStats",2); }
  9028.             print "$Center<a name=\"hours\"> </a><br />\n";
  9029.             my $title="$Message[20]";
  9030.             if ($PluginsLoaded{'GetTimeZoneTitle'}{'timezone'}) { $title.=" (GMT ".(GetTimeZoneTitle_timezone()>=0?"+":"").int(GetTimeZoneTitle_timezone()).")"; }
  9031.             &tab_head("$title",19,0,'hours');
  9032.             print "<tr><td align=\"center\">\n";
  9033.             print "<center>\n";
  9034.             
  9035.             $max_h=$max_k=1;
  9036.             for (my $ix=0; $ix<=23; $ix++) {
  9037.               #if ($_time_p[$ix]>$max_p) { $max_p=$_time_p[$ix]; }
  9038.               if ($_time_h[$ix]>$max_h) { $max_h=$_time_h[$ix]; }
  9039.               if ($_time_k[$ix]>$max_k) { $max_k=$_time_k[$ix]; }
  9040.             }
  9041.  
  9042.             # Show bars for hour
  9043.             if ($PluginsLoaded{'ShowGraph'}{'graphapplet'}) {
  9044.                 my @blocklabel=(0..23);
  9045.                 my @vallabel=("$Message[56]","$Message[57]","$Message[75]");
  9046.                 my @valcolor=("$color_p","$color_h","$color_k");
  9047.                 my @valmax=(int($max_h),int($max_h),int($max_k));
  9048.                 my @valtotal=($total_p,$total_h,$total_k);
  9049.                 my @valaverage=($average_p,$average_h,$average_k);
  9050.                 my @valdata=();
  9051.                 my $xx=0;
  9052.                 for (0..23) {
  9053.                     $valdata[$xx++]=$_time_p[$_]||0;
  9054.                     $valdata[$xx++]=$_time_h[$_]||0;
  9055.                     $valdata[$xx++]=$_time_k[$_]||0;
  9056.                 }
  9057.                 ShowGraph_graphapplet("$title","hours",$ShowHoursStats,\@blocklabel,\@vallabel,\@valcolor,\@valmax,\@valtotal,\@valaverage,\@valdata);
  9058.             }
  9059.             else {            
  9060.                 print "<table>\n";
  9061.                 print "<tr valign=\"bottom\">\n";
  9062.                 for (my $ix=0; $ix<=23; $ix++) {
  9063.                     my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  9064.                     if ($max_h > 0) { $bredde_p=int($BarHeight*$_time_p[$ix]/$max_h)+1; }
  9065.                     if ($max_h > 0) { $bredde_h=int($BarHeight*$_time_h[$ix]/$max_h)+1; }
  9066.                     if ($max_k > 0) { $bredde_k=int($BarHeight*$_time_k[$ix]/$max_k)+1; }
  9067.                     print "<td>";
  9068.                     if ($ShowHoursStats =~ /P/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vp'}\" height=\"$bredde_p\" width=\"6\"".AltTitle("$Message[56]: ".int($_time_p[$ix]))." />"; }
  9069.                     if ($ShowHoursStats =~ /H/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vh'}\" height=\"$bredde_h\" width=\"6\"".AltTitle("$Message[57]: ".int($_time_h[$ix]))." />"; }
  9070.                     if ($ShowHoursStats =~ /B/i) { print "<img align=\"bottom\" src=\"$DirIcons\/other\/$BarPng{'vk'}\" height=\"$bredde_k\" width=\"6\"".AltTitle("$Message[75]: ".Format_Bytes($_time_k[$ix]))." />"; }
  9071.                     print "</td>\n";
  9072.                 }
  9073.                 print "</tr>\n";
  9074.                 # Show hour lib
  9075.                 print "<tr".Tooltip(17).">";
  9076.                 for (my $ix=0; $ix<=23; $ix++) {
  9077.                   print "<th width=\"19\">$ix</th>\n";    # width=19 instead of 18 to avoid a MacOS browser bug.
  9078.                 }
  9079.                 print "</tr>\n";
  9080.                 # Show clock icon
  9081.                 print "<tr".Tooltip(17).">\n";
  9082.                 for (my $ix=0; $ix<=23; $ix++) {
  9083.                     my $hrs=($ix>=12?$ix-12:$ix);
  9084.                     my $hre=($ix>=12?$ix-11:$ix+1);
  9085.                     my $apm=($ix>=12?"pm":"am");
  9086.                     print "<td><img src=\"$DirIcons\/clock\/hr$hre.png\" width=\"10\" alt=\"$hrs:00 - $hre:00 $apm\" /></td>\n";
  9087.                 }
  9088.                 print "</tr>\n";
  9089.                 print "</table>\n";
  9090.             }
  9091.             print "<br />\n";
  9092.             
  9093.             # Show data array for hours
  9094.             if ($AddDataArrayShowHoursStats) {
  9095.                 print "<table width=\"650\"><tr>\n";
  9096.                 print "<td align=\"center\"><center>\n";
  9097.  
  9098.                 print "<table>\n";
  9099.                 print "<tr><td width=\"80\" bgcolor=\"#$color_TableBGRowTitle\">$Message[20]</td>";
  9100.                 if ($ShowHoursStats =~ /P/i) { print "<td width=\"80\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  9101.                 if ($ShowHoursStats =~ /H/i) { print "<td width=\"80\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  9102.                 if ($ShowHoursStats =~ /B/i) { print "<td width=\"80\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; }
  9103.                 print "</tr>";
  9104.                 for (my $ix=0; $ix<=11; $ix++) {
  9105.                     my $monthix=($ix<10?"0$ix":"$ix");
  9106.                     print "<tr>";
  9107.                     print "<td>$monthix</td>";
  9108.                     if ($ShowHoursStats =~ /P/i) { print "<td>",$_time_p[$monthix]?$_time_p[$monthix]:"0","</td>"; }
  9109.                     if ($ShowHoursStats =~ /H/i) { print "<td>",$_time_h[$monthix]?$_time_h[$monthix]:"0","</td>"; }
  9110.                     if ($ShowHoursStats =~ /B/i) { print "<td>",Format_Bytes(int($_time_k[$monthix])),"</td>"; }
  9111.                     print "</tr>\n";
  9112.                 }
  9113.                 print "</table>\n";
  9114.  
  9115.                 print "</center></td>";
  9116.                 print "<td width=\"10\"> </td>";
  9117.                 print "<td align=\"center\"><center>\n";
  9118.  
  9119.                 print "<table>\n";
  9120.                 print "<tr><td width=\"80\" bgcolor=\"#$color_TableBGRowTitle\">$Message[20]</td>";
  9121.                 if ($ShowHoursStats =~ /P/i) { print "<td width=\"80\" bgcolor=\"#$color_p\"".Tooltip(3).">$Message[56]</td>"; }
  9122.                 if ($ShowHoursStats =~ /H/i) { print "<td width=\"80\" bgcolor=\"#$color_h\"".Tooltip(4).">$Message[57]</td>"; }
  9123.                 if ($ShowHoursStats =~ /B/i) { print "<td width=\"80\" bgcolor=\"#$color_k\"".Tooltip(5).">$Message[75]</td>"; }
  9124.                 print "</tr>\n";
  9125.                 for (my $ix=12; $ix<=23; $ix++) {
  9126.                     my $monthix=($ix<10?"0$ix":"$ix");
  9127.                     print "<tr>";
  9128.                     print "<td>$monthix</td>";
  9129.                     if ($ShowHoursStats =~ /P/i) { print "<td>",$_time_p[$monthix]?$_time_p[$monthix]:"0","</td>"; }
  9130.                     if ($ShowHoursStats =~ /H/i) { print "<td>",$_time_h[$monthix]?$_time_h[$monthix]:"0","</td>"; }
  9131.                     if ($ShowHoursStats =~ /B/i) { print "<td>",Format_Bytes(int($_time_k[$monthix])),"</td>"; }
  9132.                     print "</tr>\n";
  9133.                 }
  9134.                 print "</table>\n";
  9135.  
  9136.                 print "</center></td></tr></table>\n";
  9137.                 print "<br />\n";
  9138.             }
  9139.                     
  9140.             print "</center></td></tr>\n";
  9141.             &tab_end();
  9142.         }
  9143.     
  9144.         print "\n<a name=\"who\"> </a>\n\n";
  9145.     
  9146.         # BY COUNTRY/DOMAIN
  9147.         #---------------------------
  9148.         if ($ShowDomainsStats) {
  9149.             if ($Debug) { debug("ShowDomainsStats",2); }
  9150.             print "$Center<a name=\"countries\"> </a><br />\n";
  9151.             my $title="$Message[25] ($Message[77] $MaxNbOf{'Domain'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=alldomains"):"$PROG$StaticLinks.alldomains.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>";
  9152.             &tab_head("$title",19,0,'countries');
  9153.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"$WIDTHCOLICON\"> </th><th colspan=\"2\">$Message[17]</th>";
  9154.             if ($ShowDomainsStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\"".Tooltip(3).">$Message[56]</th>"; }
  9155.             if ($ShowDomainsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th>"; }
  9156.             if ($ShowDomainsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th>"; }
  9157.             print "<th> </th>";
  9158.             print "</tr>\n";
  9159.             $total_p=$total_h=$total_k=0;
  9160.             $max_h=1; foreach (values %_domener_h) { if ($_ > $max_h) { $max_h = $_; } }
  9161.             $max_k=1; foreach (values %_domener_k) { if ($_ > $max_k) { $max_k = $_; } }
  9162.             my $count=0;
  9163.             &BuildKeyList($MaxNbOf{'Domain'},$MinHit{'Domain'},\%_domener_h,\%_domener_p);
  9164.             foreach my $key (@keylist) {
  9165.                 my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  9166.                 if ($max_h > 0) { $bredde_p=int($BarWidth*$_domener_p{$key}/$max_h)+1; }    # use max_h to enable to compare pages with hits
  9167.                 if ($_domener_p{$key} && $bredde_p==1) { $bredde_p=2; }
  9168.                 if ($max_h > 0) { $bredde_h=int($BarWidth*$_domener_h{$key}/$max_h)+1; }
  9169.                 if ($_domener_h{$key} && $bredde_h==1) { $bredde_h=2; }
  9170.                 if ($max_k > 0) { $bredde_k=int($BarWidth*($_domener_k{$key}||0)/$max_k)+1; }
  9171.                 if ($_domener_k{$key} && $bredde_k==1) { $bredde_k=2; }
  9172.                 my $newkey=lc($key);
  9173.                 if ($newkey eq 'ip' || ! $DomainsHashIDLib{$newkey}) {
  9174.                     print "<tr><td width=\"$WIDTHCOLICON\"><img src=\"$DirIcons\/flags\/ip.png\" height=\"14\"".AltTitle("$Message[0]")." /></td><td class=\"aws\">$Message[0]</td><td>$newkey</td>";
  9175.                 }
  9176.                 else {
  9177.                     print "<tr><td width=\"$WIDTHCOLICON\"><img src=\"$DirIcons\/flags\/$newkey.png\" height=\"14\"".AltTitle("$newkey")." /></td><td class=\"aws\">$DomainsHashIDLib{$newkey}</td><td>$newkey</td>";
  9178.                 }
  9179.                 if ($ShowDomainsStats =~ /P/i) { print "<td>".($_domener_p{$key}?$_domener_p{$key}:' ')."</td>"; }
  9180.                 if ($ShowDomainsStats =~ /H/i) { print "<td>$_domener_h{$key}</td>"; }
  9181.                 if ($ShowDomainsStats =~ /B/i) { print "<td>".Format_Bytes($_domener_k{$key})."</td>"; }
  9182.                 print "<td style=\"text-align:left; font-size:4px;\">";
  9183.                 if ($ShowDomainsStats =~ /P/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hp'}\" width=\"$bredde_p\" height=\"5\"".AltTitle("")." /><br />\n"; }
  9184.                 if ($ShowDomainsStats =~ /H/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hh'}\" width=\"$bredde_h\" height=\"5\"".AltTitle("")." /><br />\n"; }
  9185.                 if ($ShowDomainsStats =~ /B/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hk'}\" width=\"$bredde_k\" height=\"5\"".AltTitle("")." />"; }
  9186.                 print "</td>";
  9187.                 print "</tr>\n";
  9188.                 $total_p += $_domener_p{$key};
  9189.                 $total_h += $_domener_h{$key};
  9190.                 $total_k += $_domener_k{$key}||0;
  9191.                 $count++;
  9192.             }
  9193.             $rest_p=$TotalPages-$total_p;
  9194.             $rest_h=$TotalHits-$total_h;
  9195.             $rest_k=$TotalBytes-$total_k;
  9196.             if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {     # All other domains (known or not)
  9197.                 print "<tr><td width=\"$WIDTHCOLICON\"> </td><td colspan=\"2\" class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9198.                 if ($ShowDomainsStats =~ /P/i) { print "<td>$rest_p</td>"; }
  9199.                 if ($ShowDomainsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  9200.                 if ($ShowDomainsStats =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  9201.                 print "<td class=\"aws\"> </td>";
  9202.                 print "</tr>\n";
  9203.             }
  9204.             &tab_end();
  9205.         }
  9206.     
  9207.         # BY HOST/VISITOR
  9208.         #--------------------------
  9209.         if ($ShowHostsStats) {
  9210.             if ($Debug) { debug("ShowHostsStats",2); }
  9211.             print "$Center<a name=\"visitors\"> </a><br />\n";
  9212.             my $title="$Message[81] ($Message[77] $MaxNbOf{'HostsShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allhosts"):"$PROG$StaticLinks.allhosts.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lasthosts"):"$PROG$StaticLinks.lasthosts.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownip"):"$PROG$StaticLinks.unknownip.$StaticExt")."\"$NewLinkTarget>$Message[45]</a>";
  9213.             &tab_head("$title",19,0,'visitors');
  9214.             print "<tr bgcolor=\"#$color_TableBGRowTitle\">";
  9215.             print "<th>";
  9216.             if ($MonthRequired ne 'all') { print "$Message[81] : $TotalHostsKnown $Message[82], $TotalHostsUnknown $Message[1] - $TotalUnique $Message[11]</th>"; }
  9217.             else { print "$Message[81] : ".(scalar keys %_host_h)."</th>"; }
  9218.             &ShowHostInfo('__title__');
  9219.             if ($ShowHostsStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\"".Tooltip(3).">$Message[56]</th>"; }
  9220.             if ($ShowHostsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th>"; }
  9221.             if ($ShowHostsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th>"; }
  9222.             if ($ShowHostsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  9223.             print "</tr>\n";
  9224.             $total_p=$total_h=$total_k=0;
  9225.             my $count=0;
  9226.             &BuildKeyList($MaxNbOf{'HostsShown'},$MinHit{'Host'},\%_host_h,\%_host_p);
  9227.             foreach my $key (@keylist) {
  9228.                 print "<tr>";
  9229.                 print "<td class=\"aws\">$key</td>";
  9230.                 &ShowHostInfo($key);
  9231.                 if ($ShowHostsStats =~ /P/i) { print "<td>".($_host_p{$key}||" ")."</td>"; }
  9232.                 if ($ShowHostsStats =~ /H/i) { print "<td>$_host_h{$key}</td>"; }
  9233.                 if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($_host_k{$key})."</td>"; }
  9234.                 if ($ShowHostsStats =~ /L/i) { print "<td>".($_host_l{$key}?Format_Date($_host_l{$key},1):'-')."</td>"; }
  9235.                 print "</tr>\n";
  9236.                 $total_p += $_host_p{$key};
  9237.                 $total_h += $_host_h{$key};
  9238.                 $total_k += $_host_k{$key}||0;
  9239.                 $count++;
  9240.             }
  9241.             $rest_p=$TotalPages-$total_p;
  9242.             $rest_h=$TotalHits-$total_h;
  9243.             $rest_k=$TotalBytes-$total_k;
  9244.             if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other visitors (known or not)
  9245.                 print "<tr>";
  9246.                 print "<td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9247.                 &ShowHostInfo('');
  9248.                 if ($ShowHostsStats =~ /P/i) { print "<td>$rest_p</td>"; }
  9249.                 if ($ShowHostsStats =~ /H/i) { print "<td>$rest_h</td>"; }
  9250.                 if ($ShowHostsStats =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  9251.                 if ($ShowHostsStats =~ /L/i) { print "<td> </td>"; }
  9252.                 print "</tr>\n";
  9253.             }
  9254.             &tab_end();
  9255.         }
  9256.     
  9257.         # BY SENDER EMAIL
  9258.         #----------------------------
  9259.         if ($ShowEMailSenders) {
  9260.             &ShowEmailSendersChart($NewLinkParams,$NewLinkTarget);
  9261.         }
  9262.  
  9263.         # BY RECEIVER EMAIL
  9264.         #----------------------------
  9265.         if ($ShowEMailReceivers) {
  9266.             &ShowEmailReceiversChart($NewLinkParams,$NewLinkTarget);
  9267.         }
  9268.     
  9269.         # BY LOGIN
  9270.         #----------------------------
  9271.         if ($ShowAuthenticatedUsers) {
  9272.             if ($Debug) { debug("ShowAuthenticatedUsers",2); }
  9273.             print "$Center<a name=\"logins\"> </a><br />\n";
  9274.             my $title="$Message[94] ($Message[77] $MaxNbOf{'LoginShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=alllogins"):"$PROG$StaticLinks.alllogins.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>";
  9275.             if ($ShowAuthenticatedUsers =~ /L/i) { $title.="   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastlogins"):"$PROG$StaticLinks.lastlogins.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>"; }
  9276.             &tab_head("$title",19,0,'logins');
  9277.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$Message[94] : ".(scalar keys %_login_h)."</th>";
  9278.             &ShowUserInfo('__title__');
  9279.             if ($ShowAuthenticatedUsers =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\"".Tooltip(3).">$Message[56]</th>"; }
  9280.             if ($ShowAuthenticatedUsers =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th>"; }
  9281.             if ($ShowAuthenticatedUsers =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th>"; }
  9282.             if ($ShowAuthenticatedUsers =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  9283.             print "</tr>\n";
  9284.             $total_p=$total_h=$total_k=0;
  9285.             $max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } }
  9286.             $max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } }
  9287.             my $count=0;
  9288.             &BuildKeyList($MaxNbOf{'LoginShown'},$MinHit{'Login'},\%_login_h,\%_login_p);
  9289.             foreach my $key (@keylist) {
  9290.                 my $bredde_p=0;my $bredde_h=0;my $bredde_k=0;
  9291.                 if ($max_h > 0) { $bredde_p=int($BarWidth*$_login_p{$key}/$max_h)+1; }    # use max_h to enable to compare pages with hits
  9292.                 if ($max_h > 0) { $bredde_h=int($BarWidth*$_login_h{$key}/$max_h)+1; }
  9293.                 if ($max_k > 0) { $bredde_k=int($BarWidth*$_login_k{$key}/$max_k)+1; }
  9294.                 print "<tr><td class=\"aws\">$key</td>";
  9295.                 &ShowUserInfo($key);
  9296.                 if ($ShowAuthenticatedUsers =~ /P/i) { print "<td>".($_login_p{$key}?$_login_p{$key}:" ")."</td>"; }
  9297.                 if ($ShowAuthenticatedUsers =~ /H/i) { print "<td>$_login_h{$key}</td>"; }
  9298.                 if ($ShowAuthenticatedUsers =~ /B/i) { print "<td>".Format_Bytes($_login_k{$key})."</td>"; }
  9299.                 if ($ShowAuthenticatedUsers =~ /L/i) { print "<td>".($_login_l{$key}?Format_Date($_login_l{$key},1):'-')."</td>"; }
  9300.                 print "</tr>\n";
  9301.                 $total_p += $_login_p{$key};
  9302.                 $total_h += $_login_h{$key};
  9303.                 $total_k += $_login_k{$key};
  9304.                 $count++;
  9305.             }
  9306.             $rest_p=$TotalPages-$total_p;
  9307.             $rest_h=$TotalHits-$total_h;
  9308.             $rest_k=$TotalBytes-$total_k;
  9309.             if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other logins
  9310.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"")."$Message[125]".($PageDir eq 'rtl'?"</span>":"")."</span></td>";
  9311.                 &ShowUserInfo('');
  9312.                 if ($ShowAuthenticatedUsers =~ /P/i) { print "<td>".($rest_p?$rest_p:" ")."</td>"; }
  9313.                 if ($ShowAuthenticatedUsers =~ /H/i) { print "<td>$rest_h</td>"; }
  9314.                 if ($ShowAuthenticatedUsers =~ /B/i) { print "<td>".Format_Bytes($rest_k)."</td>"; }
  9315.                 if ($ShowAuthenticatedUsers =~ /L/i) { print "<td> </td>"; }
  9316.                 print "</tr>\n";
  9317.             }
  9318.             &tab_end();
  9319.         }
  9320.     
  9321.         # BY ROBOTS
  9322.         #----------------------------
  9323.         if ($ShowRobotsStats) {
  9324.             if ($Debug) { debug("ShowRobotStats",2); }
  9325.             print "$Center<a name=\"robots\"> </a><br />\n";
  9326.             &tab_head("$Message[53] ($Message[77] $MaxNbOf{'RobotShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=allrobots"):"$PROG$StaticLinks.allrobots.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=lastrobots"):"$PROG$StaticLinks.lastrobots.$StaticExt")."\"$NewLinkTarget>$Message[9]</a>",19,0,'robots');
  9327.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(16)."><th>".(scalar keys %_robot_h)." $Message[51]*</th>";
  9328.             if ($ShowRobotsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  9329.             if ($ShowRobotsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  9330.             if ($ShowRobotsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  9331.             print "</tr>\n";
  9332.             $total_p=$total_h=$total_k=$total_r=0;
  9333.             my $count=0;
  9334.             &BuildKeyList($MaxNbOf{'RobotShown'},$MinHit{'Robot'},\%_robot_h,\%_robot_h);
  9335.             foreach my $key (@keylist) {
  9336.                 print "<tr><td class=\"aws\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"").($RobotsHashIDLib{$key}?$RobotsHashIDLib{$key}:$key).($PageDir eq 'rtl'?"</span>":"")."</td>";
  9337.                 if ($ShowRobotsStats =~ /H/i) { print "<td>".($_robot_h{$key}-$_robot_r{$key}).($_robot_r{$key}?"+$_robot_r{$key}":"")."</td>"; }
  9338.                 if ($ShowRobotsStats =~ /B/i) { print "<td>".Format_Bytes($_robot_k{$key})."</td>"; }
  9339.                 if ($ShowRobotsStats =~ /L/i) { print "<td>".($_robot_l{$key}?Format_Date($_robot_l{$key},1):'-')."</td>"; }
  9340.                 print "</tr>\n";
  9341.                 #$total_p += $_robot_p{$key};
  9342.                 $total_h += $_robot_h{$key};
  9343.                 $total_k += $_robot_k{$key}||0;
  9344.                 $total_r += $_robot_r{$key}||0;
  9345.                 $count++;
  9346.                 }
  9347.             # For bots we need to count Totals
  9348.             my $TotalPagesRobots = 0; #foreach (values %_robot_p) { $TotalPagesRobots+=$_; }
  9349.             my $TotalHitsRobots = 0; foreach (values %_robot_h) { $TotalHitsRobots+=$_; }
  9350.             my $TotalBytesRobots = 0; foreach (values %_robot_k) { $TotalBytesRobots+=$_; }
  9351.             my $TotalRRobots = 0; foreach (values %_robot_r) { $TotalRRobots+=$_; }
  9352.             $rest_p=0;    #$rest_p=$TotalPagesRobots-$total_p;
  9353.             $rest_h=$TotalHitsRobots-$total_h;
  9354.             $rest_k=$TotalBytesRobots-$total_k;
  9355.             $rest_r=$TotalRRobots-$total_r;
  9356.             if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0 || $rest_r > 0) {    # All other robots
  9357.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9358.                 if ($ShowRobotsStats =~ /H/i) { print "<td>".($rest_h-$rest_r).($rest_r?"+$rest_r":"")."</td>"; }
  9359.                 if ($ShowRobotsStats =~ /B/i) { print "<td>".(Format_Bytes($rest_k))."</td>"; }
  9360.                 if ($ShowRobotsStats =~ /L/i) { print "<td> </td>"; }
  9361.                 print "</tr>\n";
  9362.             }
  9363.             &tab_end("* $Message[156]".($TotalRRobots?" $Message[157]":""));
  9364.         }
  9365.  
  9366.         # BY WORMS
  9367.         #----------------------------
  9368.         if ($ShowWormsStats) {
  9369.             if ($Debug) { debug("ShowWormsStats",2); }
  9370.             print "$Center<a name=\"worms\"> </a><br />\n";
  9371.             &tab_head("$Message[163] ($Message[77] $MaxNbOf{'WormsShown'})",19,0,'worms');
  9372.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(21).">";
  9373.             print "<th>".(scalar keys %_worm_h)." $Message[164]*</th>";
  9374.             print "<th>$Message[167]</th>";
  9375.             if ($ShowWormsStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  9376.             if ($ShowWormsStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  9377.             if ($ShowWormsStats =~ /L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  9378.             print "</tr>\n";
  9379.             $total_p=$total_h=$total_k=0;
  9380.             my $count=0;
  9381.             &BuildKeyList($MaxNbOf{'WormsShown'},$MinHit{'Worm'},\%_worm_h,\%_worm_h);
  9382.             foreach my $key (@keylist) {
  9383.                 print "<tr>";
  9384.                 print "<td class=\"aws\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"").($WormsHashLib{$key}?$WormsHashLib{$key}:$key).($PageDir eq 'rtl'?"</span>":"")."</td>";
  9385.                 print "<td class=\"aws\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"").($WormsHashTarget{$key}?$WormsHashTarget{$key}:$key).($PageDir eq 'rtl'?"</span>":"")."</td>";
  9386.                 if ($ShowWormsStats =~ /H/i) { print "<td>".$_worm_h{$key}."</td>"; }
  9387.                 if ($ShowWormsStats =~ /B/i) { print "<td>".Format_Bytes($_worm_k{$key})."</td>"; }
  9388.                 if ($ShowWormsStats =~ /L/i) { print "<td>".($_worm_l{$key}?Format_Date($_worm_l{$key},1):'-')."</td>"; }
  9389.                 print "</tr>\n";
  9390.                 #$total_p += $_worm_p{$key};
  9391.                 $total_h += $_worm_h{$key};
  9392.                 $total_k += $_worm_k{$key}||0;
  9393.                 $count++;
  9394.                 }
  9395.             # For worms we need to count Totals
  9396.             my $TotalPagesWorms = 0; #foreach (values %_worm_p) { $TotalPagesWorms+=$_; }
  9397.             my $TotalHitsWorms = 0; foreach (values %_worm_h) { $TotalHitsWorms+=$_; }
  9398.             my $TotalBytesWorms = 0; foreach (values %_worm_k) { $TotalBytesWorms+=$_; }
  9399.             $rest_p=0;    #$rest_p=$TotalPagesRobots-$total_p;
  9400.             $rest_h=$TotalHitsWorms-$total_h;
  9401.             $rest_k=$TotalBytesWorms-$total_k;
  9402.             if ($rest_p > 0 || $rest_h > 0 || $rest_k > 0) {    # All other worms
  9403.                 print "<tr>";
  9404.                 print "<td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9405.                 print "<td class=\"aws\">-</td>";
  9406.                 if ($ShowWormsStats =~ /H/i) { print "<td>".($rest_h)."</td>"; }
  9407.                 if ($ShowWormsStats =~ /B/i) { print "<td>".(Format_Bytes($rest_k))."</td>"; }
  9408.                 if ($ShowWormsStats =~ /L/i) { print "<td> </td>"; }
  9409.                 print "</tr>\n";
  9410.             }
  9411.             &tab_end("* $Message[158]");
  9412.         }
  9413.     
  9414.         print "\n<a name=\"how\"> </a>\n\n";
  9415.     
  9416.         # BY SESSION
  9417.         #----------------------------
  9418.         if ($ShowSessionsStats) {
  9419.             if ($Debug) { debug("ShowSessionsStats",2); }
  9420.             print "$Center<a name=\"sessions\"> </a><br />\n";
  9421.             my $title="$Message[117]";
  9422.             &tab_head($title,19,0,'sessions');
  9423.             my $Totals=0; foreach (@SessionsRange) { $average_s+=($_session{$_}||0)*$SessionsAverage{$_}; $Totals+=$_session{$_}||0; }
  9424.             if ($Totals) { $average_s=int($average_s/$Totals); }
  9425.             else { $average_s='?'; }
  9426.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(1)."><th>$Message[10]: $TotalVisits - $Message[96]: $average_s s</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[10]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[15]</th></tr>\n";
  9427.             $average_s=0;
  9428.             $total_s=0;
  9429.             my $count=0;
  9430.             foreach my $key (@SessionsRange) {
  9431.                 my $p=0;
  9432.                 if ($TotalVisits) { $p=int($_session{$key}/$TotalVisits*1000)/10; }
  9433.                 $total_s+=$_session{$key}||0;
  9434.                 print "<tr><td class=\"aws\">$key</td>";
  9435.                 print "<td>".($_session{$key}?$_session{$key}:" ")."</td>";
  9436.                 print "<td>".($_session{$key}?"$p %":" ")."</td>";
  9437.                 print "</tr>\n";
  9438.                 $count++;
  9439.             }
  9440.             $rest_s=$TotalVisits-$total_s;
  9441.             if ($rest_s > 0) {    # All others sessions
  9442.                 my $p=0;
  9443.                 if ($TotalVisits) { $p=int($rest_s/$TotalVisits*1000)/10; }
  9444.                 print "<tr".Tooltip(20)."><td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td>";
  9445.                 print "<td>$rest_s</td>";
  9446.                 print "<td>".($rest_s?"$p %":" ")."</td>";
  9447.                 print "</tr>\n";
  9448.             }
  9449.             &tab_end();
  9450.         }
  9451.     
  9452.         # BY FILE TYPE
  9453.         #-------------------------
  9454.         if ($ShowFileTypesStats) {
  9455.             if ($Debug) { debug("ShowFileTypesStatsCompressionStats",2); }
  9456.             print "$Center<a name=\"filetypes\"> </a><br />\n";
  9457.             my $Totalh=0; foreach (keys %_filetypes_h) { $Totalh+=$_filetypes_h{$_}; }
  9458.             my $Totalk=0; foreach (keys %_filetypes_k) { $Totalk+=$_filetypes_k{$_}; }
  9459.             my $title="$Message[73]";
  9460.             if ($ShowFileTypesStats =~ /C/i) { $title.=" - $Message[98]"; }
  9461.             &tab_head("$title",19,0,'filetypes');
  9462.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"3\">$Message[73]</th>";
  9463.             if ($ShowFileTypesStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\"".Tooltip(4).">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>"; }
  9464.             if ($ShowFileTypesStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\"".Tooltip(5).">$Message[75]</th><th bgcolor=\"#$color_k\" width=\"80\">$Message[15]</th>"; }
  9465.             if ($ShowFileTypesStats =~ /C/i) { print "<th bgcolor=\"#$color_k\" width=\"120\">$Message[100]</th><th bgcolor=\"#$color_k\" width=\"120\">$Message[101]</th><th bgcolor=\"#$color_k\" width=\"120\">$Message[99]</th>"; }
  9466.             print "</tr>\n";
  9467.             my $total_con=0; my $total_cre=0;
  9468.             my $count=0;
  9469.             &BuildKeyList($MaxRowsInHTMLOutput,1,\%_filetypes_h,\%_filetypes_h);
  9470.             foreach my $key (@keylist) {
  9471.                 my $p_h=' '; my $p_k=' ';
  9472.                 if ($Totalh) { $p_h=int($_filetypes_h{$key}/$Totalh*1000)/10; $p_h="$p_h %"; }
  9473.                 if ($Totalk) { $p_k=int($_filetypes_k{$key}/$Totalk*1000)/10; $p_k="$p_k %"; }
  9474.                 if ($key eq 'Unknown') {
  9475.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/mime\/unknown.png\"".AltTitle("")." /></td><td class=\"aws\" colspan=\"2\"><span style=\"color: #$color_other\">$Message[0]</span></td>";
  9476.                 }
  9477.                 else {
  9478.                     my $nameicon=$MimeHashIcon{$key}||"notavailable";
  9479.                     my $nametype=$MimeHashLib{$MimeHashFamily{$key}||""}||" ";
  9480.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/mime\/$nameicon.png\"".AltTitle("")." /></td><td class=\"aws\">$key</td>";
  9481.                     print "<td class=\"aws\">$nametype</td>";
  9482.                 }
  9483.                 if ($ShowFileTypesStats =~ /H/i) { print "<td>$_filetypes_h{$key}</td><td>$p_h</td>"; }
  9484.                 if ($ShowFileTypesStats =~ /B/i) { print "<td>".Format_Bytes($_filetypes_k{$key})."</td><td>$p_k</td>"; }
  9485.                 if ($ShowFileTypesStats =~ /C/i) {
  9486.                     if ($_filetypes_gz_in{$key}) {
  9487.                         my $percent=int(100*(1-$_filetypes_gz_out{$key}/$_filetypes_gz_in{$key}));
  9488.                         printf("<td>%s</td><td>%s</td><td>%s (%s%)</td>",Format_Bytes($_filetypes_gz_in{$key}),Format_Bytes($_filetypes_gz_out{$key}),Format_Bytes($_filetypes_gz_in{$key}-$_filetypes_gz_out{$key}),$percent);
  9489.                         $total_con+=$_filetypes_gz_in{$key};
  9490.                         $total_cre+=$_filetypes_gz_out{$key};
  9491.                     }
  9492.                     else {
  9493.                         print "<td> </td><td> </td><td> </td>";
  9494.                     }
  9495.                 }
  9496.                 print "</tr>\n";
  9497.                 $count++;
  9498.             }
  9499.             # Add total (only usefull if compression is enabled)
  9500.             if ($ShowFileTypesStats =~ /C/i) {    
  9501.                 my $colspan=3;
  9502.                  if ($ShowFileTypesStats =~ /H/i) { $colspan+=2; }
  9503.                  if ($ShowFileTypesStats =~ /B/i) { $colspan+=2; }
  9504.                  print "<tr>";
  9505.                  print "<td class=\"aws\" colspan=\"$colspan\"><b>$Message[98]</b></td>";
  9506.                  if ($ShowFileTypesStats =~ /C/i) {
  9507.                     if ($total_con) {
  9508.                         my $percent=int(100*(1-$total_cre/$total_con));
  9509.                         printf("<td>%s</td><td>%s</td><td>%s (%s%)</td>",Format_Bytes($total_con),Format_Bytes($total_cre),Format_Bytes($total_con-$total_cre),$percent);
  9510.                     }
  9511.                     else {
  9512.                         print "<td> </td><td> </td><td> </td>";
  9513.                     }
  9514.                  }
  9515.                  print "</tr>\n";
  9516.             }
  9517.             &tab_end();
  9518.         }
  9519.     
  9520.         # BY FILE SIZE
  9521.         #-------------------------
  9522.         if ($ShowFileSizesStats) {
  9523.     
  9524.         }
  9525.     
  9526.         # BY FILE/URL
  9527.         #-------------------------
  9528.         if ($ShowPagesStats) {
  9529.             if ($Debug) { debug("ShowPagesStats (MaxNbOf{'PageShown'}=$MaxNbOf{'PageShown'} TotalDifferentPages=$TotalDifferentPages)",2); }
  9530.             print "$Center<a name=\"urls\"> </a><a name=\"entry\"> </a><a name=\"exit\"> </a><br />\n";
  9531.             my $title="$Message[19] ($Message[77] $MaxNbOf{'PageShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urldetail"):"$PROG$StaticLinks.urldetail.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>";
  9532.             if ($ShowPagesStats =~ /E/i) { $title.="   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urlentry"):"$PROG$StaticLinks.urlentry.$StaticExt")."\"$NewLinkTarget>$Message[104]</a>"; }
  9533.             if ($ShowPagesStats =~ /X/i) { $title.="   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=urlexit"):"$PROG$StaticLinks.urlexit.$StaticExt")."\"$NewLinkTarget>$Message[116]</a>"; }
  9534.             &tab_head("$title",19,0,'urls');
  9535.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$TotalDifferentPages $Message[28]</th>";
  9536.             if ($ShowPagesStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[29]</th>"; }
  9537.             if ($ShowPagesStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[106]</th>"; }
  9538.             if ($ShowPagesStats =~ /E/i) { print "<th bgcolor=\"#$color_e\" width=\"80\">$Message[104]</th>"; }
  9539.             if ($ShowPagesStats =~ /X/i) { print "<th bgcolor=\"#$color_x\" width=\"80\">$Message[116]</th>"; }
  9540.             # Call to plugins' function ShowPagesAddField
  9541.             foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  9542.                 my $function="ShowPagesAddField_$pluginname('title')";
  9543.                 eval("$function");
  9544.             }
  9545.             print "<th> </th></tr>\n";
  9546.             $total_p=$total_e=$total_x=$total_k=0;
  9547.             $max_p=1; $max_k=1;
  9548.             my $count=0;
  9549.             &BuildKeyList($MaxNbOf{'PageShown'},$MinHit{'File'},\%_url_p,\%_url_p);
  9550.             foreach my $key (@keylist) {
  9551.                 if ($_url_p{$key} > $max_p) { $max_p = $_url_p{$key}; }
  9552.                 if ($_url_k{$key}/($_url_p{$key}||1) > $max_k) { $max_k = $_url_k{$key}/($_url_p{$key}||1); }
  9553.             }
  9554.             foreach my $key (@keylist) {
  9555.                 print "<tr><td class=\"aws\">";
  9556.                 &ShowURLInfo($key);
  9557.                 print "</td>";
  9558.                 my $bredde_p=0; my $bredde_e=0; my $bredde_x=0; my $bredde_k=0;
  9559.                 if ($max_p > 0) { $bredde_p=int($BarWidth*($_url_p{$key}||0)/$max_p)+1; }
  9560.                 if (($bredde_p==1) && $_url_p{$key}) { $bredde_p=2; }
  9561.                 if ($max_p > 0) { $bredde_e=int($BarWidth*($_url_e{$key}||0)/$max_p)+1; }
  9562.                 if (($bredde_e==1) && $_url_e{$key}) { $bredde_e=2; }
  9563.                 if ($max_p > 0) { $bredde_x=int($BarWidth*($_url_x{$key}||0)/$max_p)+1; }
  9564.                 if (($bredde_x==1) && $_url_x{$key}) { $bredde_x=2; }
  9565.                 if ($max_k > 0) { $bredde_k=int($BarWidth*(($_url_k{$key}||0)/($_url_p{$key}||1))/$max_k)+1; }
  9566.                 if (($bredde_k==1) && $_url_k{$key}) { $bredde_k=2; }
  9567.                 if ($ShowPagesStats =~ /P/i) { print "<td>$_url_p{$key}</td>"; }
  9568.                 if ($ShowPagesStats =~ /B/i) { print "<td>".($_url_k{$key}?Format_Bytes($_url_k{$key}/($_url_p{$key}||1)):" ")."</td>"; }
  9569.                 if ($ShowPagesStats =~ /E/i) { print "<td>".($_url_e{$key}?$_url_e{$key}:" ")."</td>"; }
  9570.                 if ($ShowPagesStats =~ /X/i) { print "<td>".($_url_x{$key}?$_url_x{$key}:" ")."</td>"; }
  9571.                 # Call to plugins' function ShowPagesAddField
  9572.                 foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  9573.                     my $function="ShowPagesAddField_$pluginname('$key')";
  9574.                     eval("$function");
  9575.                 }
  9576.                 print "<td style=\"text-align:left; font-size:4px;\">";
  9577.                 if ($ShowPagesStats =~ /P/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hp'}\" width=\"$bredde_p\" height=\"4\"".AltTitle("")." /><br />"; }
  9578.                 if ($ShowPagesStats =~ /B/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hk'}\" width=\"$bredde_k\" height=\"4\"".AltTitle("")." /><br />"; }
  9579.                 if ($ShowPagesStats =~ /E/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'he'}\" width=\"$bredde_e\" height=\"4\"".AltTitle("")." /><br />"; }
  9580.                 if ($ShowPagesStats =~ /X/i) { print "<img src=\"$DirIcons\/other\/$BarPng{'hx'}\" width=\"$bredde_x\" height=\"4\"".AltTitle("")." />"; }
  9581.                 print "</td></tr>\n";
  9582.                 $total_p += $_url_p{$key};
  9583.                 $total_e += $_url_e{$key};
  9584.                 $total_x += $_url_x{$key};
  9585.                 $total_k += $_url_k{$key};
  9586.                 $count++;
  9587.             }
  9588.             $rest_p=$TotalPages-$total_p;
  9589.             $rest_e=$TotalEntries-$total_e;
  9590.             $rest_x=$TotalExits-$total_x;
  9591.             $rest_k=$TotalBytesPages-$total_k;
  9592.             if ($rest_p > 0 || $rest_k > 0 || $rest_e > 0 || $rest_x > 0) {    # All other urls
  9593.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9594.                 if ($ShowPagesStats =~ /P/i) { print "<td>$rest_p</td>"; }
  9595.                 if ($ShowPagesStats =~ /B/i) { print "<td>".($rest_k?Format_Bytes($rest_k/($rest_p||1)):" ")."</td>"; }
  9596.                 if ($ShowPagesStats =~ /E/i) { print "<td>".($rest_e?$rest_e:" ")."</td>"; }
  9597.                 if ($ShowPagesStats =~ /X/i) { print "<td>".($rest_x?$rest_x:" ")."</td>"; }
  9598.                 # Call to plugins' function ShowPagesAddField
  9599.                 foreach my $pluginname (keys %{$PluginsLoaded{'ShowPagesAddField'}})  {
  9600.                     my $function="ShowPagesAddField_$pluginname('')";
  9601.                     eval("$function");
  9602.                 }
  9603.                 print "<td> </td></tr>\n";
  9604.             }
  9605.             &tab_end();
  9606.         }
  9607.     
  9608.         # BY OS
  9609.         #----------------------------
  9610.         if ($ShowOSStats) {
  9611.             if ($Debug) { debug("ShowOSStats",2); }
  9612.             print "$Center<a name=\"os\"> </a><br />\n";
  9613.             my $Totalh=0; my %new_os_h=();
  9614.             OSLOOP: foreach my $key (keys %_os_h) {
  9615.                 $Totalh+=$_os_h{$key};
  9616.                 foreach my $family (@OSFamily) { if ($key =~ /^$family/i) { $new_os_h{"${family}cumul"}+=$_os_h{$key}; next OSLOOP; } }
  9617.                 $new_os_h{$key}+=$_os_h{$key};
  9618.             }
  9619.             my $title="$Message[59] ($Message[77] $MaxNbOf{'OsShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=osdetail"):"$PROG$StaticLinks.osdetail.$StaticExt")."\"$NewLinkTarget>$Message[80]/$Message[58]</a>   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownos"):"$PROG$StaticLinks.unknownos.$StaticExt")."\"$NewLinkTarget>$Message[0]</a>";
  9620.             &tab_head("$title",19,0,'os');
  9621.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"$WIDTHCOLICON\"> </th><th>$Message[59]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th></tr>\n";
  9622.             $total_h=0;
  9623.             my $count=0;
  9624.             &BuildKeyList($MaxNbOf{'OsShown'},$MinHit{'Os'},\%new_os_h,\%new_os_h);
  9625.             foreach my $key (@keylist) {
  9626.                 my $p=' ';
  9627.                 if ($Totalh) { $p=int($new_os_h{$key}/$Totalh*1000)/10; $p="$p %"; }
  9628.                 if ($key eq 'Unknown') {
  9629.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/os\/unknown.png\"".AltTitle("")." /></td><td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td><td>$_os_h{$key}</td><td>$p</td></tr>\n";
  9630.                 }
  9631.                 else {
  9632.                     my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i;
  9633.                     my $libos=$OSHashLib{$keywithoutcumul}||$keywithoutcumul;
  9634.                     my $nameicon=$keywithoutcumul; $nameicon =~ s/[^\w]//g;
  9635.                     # TODO Use OSFamilyLib
  9636.                     if ($libos eq 'win') { $libos="<b>Windows</b>"; }
  9637.                     if ($libos eq 'mac') { $libos="<b>Macintosh</b>"; }
  9638.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/os\/$nameicon.png\"".AltTitle("")." /></td><td class=\"aws\">$libos</td><td>$new_os_h{$key}</td><td>$p</td></tr>\n";
  9639.                 }
  9640.                 $total_h += $new_os_h{$key};
  9641.                 $count++;
  9642.             }
  9643.             if ($Debug) { debug("Total real / shown : $Totalh / $total_h",2); }
  9644.             $rest_h=$Totalh-$total_h;
  9645.             if ($rest_h > 0) {
  9646.                 my $p;
  9647.                 if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; }
  9648.                 print "<tr>";
  9649.                 print "<td> </td>";
  9650.                 print "<td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td><td>$rest_h</td>";
  9651.                 print "<td>$p %</td></tr>\n";
  9652.             }
  9653.             &tab_end();
  9654.         }
  9655.         
  9656.         # BY BROWSER
  9657.         #----------------------------
  9658.         if ($ShowBrowsersStats) {
  9659.             if ($Debug) { debug("ShowBrowsersStats",2); }
  9660.             print "$Center<a name=\"browsers\"> </a><br />\n";
  9661.             my $Totalh=0; my %new_browser_h=();
  9662.             BROWSERLOOP: foreach my $key (keys %_browser_h) {
  9663.                 $Totalh+=$_browser_h{$key};
  9664.                 foreach my $family (keys %BrowsersFamily) { if ($key =~ /^$family/i) { $new_browser_h{"${family}cumul"}+=$_browser_h{$key}; next BROWSERLOOP; } }
  9665.                 $new_browser_h{$key}+=$_browser_h{$key};
  9666.             }
  9667.             my $title="$Message[21] ($Message[77] $MaxNbOf{'BrowsersShown'})   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=browserdetail"):"$PROG$StaticLinks.browserdetail.$StaticExt")."\"$NewLinkTarget>$Message[80]/$Message[58]</a>   -   <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=unknownbrowser"):"$PROG$StaticLinks.unknownbrowser.$StaticExt")."\"$NewLinkTarget>$Message[0]</a>";
  9668.             &tab_head("$title",19,0,'browsers');
  9669.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th width=\"$WIDTHCOLICON\"> </th><th>$Message[21]</th><th width=\"80\">$Message[111]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th></tr>\n";
  9670.             $total_h=0;
  9671.             my $count=0;
  9672.             &BuildKeyList($MaxNbOf{'BrowsersShown'},$MinHit{'Browser'},\%new_browser_h,\%new_browser_h);
  9673.             foreach my $key (@keylist) {
  9674.                 my $p=' ';
  9675.                 if ($Totalh) { $p=int($new_browser_h{$key}/$Totalh*1000)/10; $p="$p %"; }
  9676.                 if ($key eq 'Unknown') {
  9677.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/unknown.png\"".AltTitle("")." /></td><td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td><td width=\"80\">?</td><td>$_browser_h{$key}</td><td>$p</td></tr>\n";
  9678.                 }
  9679.                 else {
  9680.                     my $keywithoutcumul=$key; $keywithoutcumul =~ s/cumul$//i;
  9681.                     my $libbrowser=$BrowsersHashIDLib{$keywithoutcumul}||$keywithoutcumul;
  9682.                     my $nameicon=$BrowsersHashIcon{$keywithoutcumul}||"notavailable";
  9683.                     if ($BrowsersFamily{$keywithoutcumul}) { $libbrowser="<b>$libbrowser</b>"; }
  9684.                     print "<tr><td".($count?"":" width=\"$WIDTHCOLICON\"")."><img src=\"$DirIcons\/browser\/$nameicon.png\"".AltTitle("")." /></td><td class=\"aws\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"")."$libbrowser".($PageDir eq 'rtl'?"</span>":"")."</td><td>".($BrowsersHereAreGrabbers{$key}?"<b>$Message[112]</b>":"$Message[113]")."</td><td>$new_browser_h{$key}</td><td>$p</td></tr>\n";
  9685.                 }
  9686.                 $total_h += $new_browser_h{$key};
  9687.                 $count++;
  9688.             }
  9689.             if ($Debug) { debug("Total real / shown : $Totalh / $total_h",2); }
  9690.             $rest_h=$Totalh-$total_h;
  9691.             if ($rest_h > 0) {
  9692.                 my $p;
  9693.                 if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; }
  9694.                 print "<tr>";
  9695.                 print "<td> </td>";
  9696.                 print "<td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td><td> </td><td>$rest_h</td>";
  9697.                 print "<td>$p %</td></tr>\n";
  9698.             }
  9699.             &tab_end();
  9700.         }
  9701.     
  9702.         # BY SCREEN SIZE
  9703.         #----------------------------
  9704.         if ($ShowScreenSizeStats) {
  9705.             if ($Debug) { debug("ShowScreenSizeStats",2); }
  9706.             print "$Center<a name=\"screensizes\"> </a><br />\n";
  9707.             my $Totalh=0; foreach (keys %_screensize_h) { $Totalh+=$_screensize_h{$_}; }
  9708.             my $title="$Message[135] ($Message[77] $MaxNbOf{'ScreenSizesShown'})";
  9709.             &tab_head("$title",0,0,'screensizes');
  9710.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$Message[135]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th></tr>\n";
  9711.             my $total_h=0;
  9712.             my $count=0;
  9713.             &BuildKeyList($MaxNbOf{'ScreenSizesShown'},$MinHit{'ScreenSize'},\%_screensize_h,\%_screensize_h);
  9714.             foreach my $key (@keylist) {
  9715.                 my $p=' ';
  9716.                 if ($Totalh) { $p=int($_screensize_h{$key}/$Totalh*1000)/10; $p="$p %"; }
  9717.                 $total_h+=$_screensize_h{$key}||0;
  9718.                 print "<tr>";
  9719.                 if ($key eq 'Unknown') {
  9720.                     print "<td class=\"aws\"><span style=\"color: #$color_other\">$Message[0]</span></td>";
  9721.                     print "<td>$p</td>";
  9722.                     }
  9723.                 else {
  9724.                     my $screensize=$key;
  9725.                     print "<td class=\"aws\">$screensize</td>";
  9726.                     print "<td>$p</td>";
  9727.                 }
  9728.                 print "</tr>\n";
  9729.                 $count++;
  9730.             }
  9731.             $rest_h=$Totalh-$total_h;
  9732.             if ($rest_h > 0) {    # All others sessions
  9733.                 my $p=0;
  9734.                 if ($Totalh) { $p=int($rest_h/$Totalh*1000)/10; }
  9735.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[2]</span></td>";
  9736.                 print "<td>".($rest_h?"$p %":" ")."</td>";
  9737.                 print "</tr>\n";
  9738.             }
  9739.             &tab_end();
  9740.         }
  9741.  
  9742.         print "\n<a name=\"refering\"> </a>\n\n";
  9743.     
  9744.         # BY REFERENCE
  9745.         #---------------------------
  9746.         if ($ShowOriginStats) {
  9747.             if ($Debug) { debug("ShowOriginStats",2); }
  9748.             print "$Center<a name=\"referer\"> </a><br />\n";
  9749.             my $Totalp=0; foreach (0..5) { $Totalp+=($_ != 4 || $IncludeInternalLinksInOriginSection)?$_from_p[$_]:0; }
  9750.             my $Totalh=0; foreach (0..5) { $Totalh+=($_ != 4 || $IncludeInternalLinksInOriginSection)?$_from_h[$_]:0; }
  9751.             &tab_head($Message[36],19,0,'referer');
  9752.             my @p_p=(0,0,0,0,0,0);
  9753.             if ($Totalp > 0) {
  9754.                 $p_p[0]=int($_from_p[0]/$Totalp*1000)/10;
  9755.                 $p_p[1]=int($_from_p[1]/$Totalp*1000)/10;
  9756.                 $p_p[2]=int($_from_p[2]/$Totalp*1000)/10;
  9757.                 $p_p[3]=int($_from_p[3]/$Totalp*1000)/10;
  9758.                 $p_p[4]=int($_from_p[4]/$Totalp*1000)/10;
  9759.                 $p_p[5]=int($_from_p[5]/$Totalp*1000)/10;
  9760.             }
  9761.             my @p_h=(0,0,0,0,0,0);
  9762.             if ($Totalh > 0) {
  9763.                 $p_h[0]=int($_from_h[0]/$Totalh*1000)/10;
  9764.                 $p_h[1]=int($_from_h[1]/$Totalh*1000)/10;
  9765.                 $p_h[2]=int($_from_h[2]/$Totalh*1000)/10;
  9766.                 $p_h[3]=int($_from_h[3]/$Totalh*1000)/10;
  9767.                 $p_h[4]=int($_from_h[4]/$Totalh*1000)/10;
  9768.                 $p_h[5]=int($_from_h[5]/$Totalh*1000)/10;
  9769.             }
  9770.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$Message[37]</th>";
  9771.             if ($ShowOriginStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th><th bgcolor=\"#$color_p\" width=\"80\">$Message[15]</th>"; }
  9772.             if ($ShowOriginStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>"; }
  9773.             print "</tr>\n";
  9774.             #------- Referrals by direct address/bookmarks
  9775.             print "<tr><td class=\"aws\"><b>$Message[38]</b></td>";
  9776.             if ($ShowOriginStats =~ /P/i) { print "<td>".($_from_p[0]?$_from_p[0]:" ")."</td><td>".($_from_p[0]?"$p_p[0] %":" ")."</td>"; }
  9777.             if ($ShowOriginStats =~ /H/i) { print "<td>".($_from_h[0]?$_from_h[0]:" ")."</td><td>".($_from_h[0]?"$p_h[0] %":" ")."</td>"; }
  9778.             print "</tr>\n";
  9779.             #------- Referrals by news group
  9780.             print "<tr><td class=\"aws\"><b>$Message[107]</b></td>";
  9781.             if ($ShowOriginStats =~ /P/i) { print "<td>".($_from_p[5]?$_from_p[5]:" ")."</td><td>".($_from_p[5]?"$p_p[5] %":" ")."</td>"; }
  9782.             if ($ShowOriginStats =~ /H/i) { print "<td>".($_from_h[5]?$_from_h[5]:" ")."</td><td>".($_from_h[5]?"$p_h[5] %":" ")."</td>"; }
  9783.             print "</tr>\n";
  9784.             #------- Referrals by search engines
  9785.             print "<tr".Tooltip(13)."><td class=\"aws\"><b>$Message[40]</b> - <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=refererse"):"$PROG$StaticLinks.refererse.$StaticExt")."\"$NewLinkTarget>$Message[80]</a><br />\n";
  9786.             if (scalar keys %_se_referrals_h) {
  9787.                 print "<table>\n";
  9788.                 $total_p=0; $total_h=0;
  9789.                 my $count=0;
  9790.                 &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_se_referrals_h,((scalar keys %_se_referrals_p)?\%_se_referrals_p:\%_se_referrals_h));
  9791.                 foreach my $key (@keylist) {
  9792.                     my $newreferer=CleanFromCSSA($SearchEnginesHashLib{$key}||$key);
  9793.                     print "<tr><td class=\"aws\">- $newreferer</td>";
  9794.                     print "<td>".($_se_referrals_p{$key}?$_se_referrals_p{$key}:'0')."</td>";
  9795.                     print "<td>$_se_referrals_h{$key}</td>";
  9796.                     print "</tr>\n";
  9797.                     $total_p += $_se_referrals_p{$key};
  9798.                     $total_h += $_se_referrals_h{$key};
  9799.                     $count++;
  9800.                 }
  9801.                 if ($Debug) { debug("Total real / shown : $TotalSearchEnginesPages / $total_p -  $TotalSearchEnginesHits / $total_h",2); }
  9802.                 $rest_p=$TotalSearchEnginesPages-$total_p;
  9803.                 $rest_h=$TotalSearchEnginesHits-$total_h;
  9804.                 if ($rest_p > 0 || $rest_h > 0) {
  9805.                     print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">- $Message[2]</span></td>";
  9806.                     print "<td>$rest_p</td>";
  9807.                     print "<td>$rest_h</td>";
  9808.                     print "</tr>\n";
  9809.                 }
  9810.                 print "</table>";
  9811.             }
  9812.             print "</td>\n";
  9813.             if ($ShowOriginStats =~ /P/i) { print "<td valign=\"top\">".($_from_p[2]?$_from_p[2]:" ")."</td><td valign=\"top\">".($_from_p[2]?"$p_p[2] %":" ")."</td>"; }
  9814.             if ($ShowOriginStats =~ /H/i) { print "<td valign=\"top\">".($_from_h[2]?$_from_h[2]:" ")."</td><td valign=\"top\">".($_from_h[2]?"$p_h[2] %":" ")."</td>"; }
  9815.             print "</tr>\n";
  9816.             #------- Referrals by external HTML link
  9817.             print "<tr".Tooltip(14)."><td class=\"aws\"><b>$Message[41]</b> - <a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=refererpages"):"$PROG$StaticLinks.refererpages.$StaticExt")."\"$NewLinkTarget>$Message[80]</a><br />\n";
  9818.             if (scalar keys %_pagesrefs_h) {
  9819.                 print "<table>\n";
  9820.                 $total_p=0; $total_h=0;
  9821.                 my $count=0;
  9822.                 &BuildKeyList($MaxNbOf{'RefererShown'},$MinHit{'Refer'},\%_pagesrefs_h,((scalar keys %_pagesrefs_p)?\%_pagesrefs_p:\%_pagesrefs_h));
  9823.                 foreach my $key (@keylist) {
  9824.                     print "<tr><td class=\"aws\">- ";
  9825.                     &ShowURLInfo($key);
  9826.                     print "</td>";
  9827.                     print "<td>".($_pagesrefs_p{$key}?$_pagesrefs_p{$key}:'0')."</td>";
  9828.                     print "<td>$_pagesrefs_h{$key}</td>";
  9829.                     print "</tr>\n";
  9830.                     $total_p += $_pagesrefs_p{$key};
  9831.                     $total_h += $_pagesrefs_h{$key};
  9832.                     $count++;
  9833.                 }
  9834.                 if ($Debug) { debug("Total real / shown : $TotalRefererPages / $total_p - $TotalRefererHits / $total_h",2); }
  9835.                 $rest_p=$TotalRefererPages-$total_p;
  9836.                 $rest_h=$TotalRefererHits-$total_h;
  9837.                 if ($rest_p > 0 || $rest_h > 0) {
  9838.                     print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">- $Message[2]</span></td>";
  9839.                     print "<td>$rest_p</td>";
  9840.                     print "<td>$rest_h</td>";
  9841.                     print "</tr>\n";
  9842.                 }
  9843.                 print "</table>";
  9844.             }
  9845.             print "</td>\n";
  9846.             if ($ShowOriginStats =~ /P/i) { print "<td valign=\"top\">".($_from_p[3]?$_from_p[3]:" ")."</td><td valign=\"top\">".($_from_p[3]?"$p_p[3] %":" ")."</td>"; }
  9847.             if ($ShowOriginStats =~ /H/i) { print "<td valign=\"top\">".($_from_h[3]?$_from_h[3]:" ")."</td><td valign=\"top\">".($_from_h[3]?"$p_h[3] %":" ")."</td>"; }
  9848.             print "</tr>\n";
  9849.             #------- Referrals by internal HTML link
  9850.             if ($IncludeInternalLinksInOriginSection) {
  9851.                 print "<tr><td class=\"aws\"><b>$Message[42]</b></td>";
  9852.                 if ($ShowOriginStats =~ /P/i) { print "<td>".($_from_p[4]?$_from_p[4]:" ")."</td><td>".($_from_p[4]?"$p_p[4] %":" ")."</td>"; }
  9853.                 if ($ShowOriginStats =~ /H/i) { print "<td>".($_from_h[4]?$_from_h[4]:" ")."</td><td>".($_from_h[4]?"$p_h[4] %":" ")."</td>"; }
  9854.                 print "</tr>\n";
  9855.             }
  9856.             #------- Unknown origin
  9857.             print "<tr><td class=\"aws\"><b>$Message[39]</b></td>";
  9858.             if ($ShowOriginStats =~ /P/i) { print "<td>".($_from_p[1]?$_from_p[1]:" ")."</td><td>".($_from_p[1]?"$p_p[1] %":" ")."</td>"; }
  9859.             if ($ShowOriginStats =~ /H/i) { print "<td>".($_from_h[1]?$_from_h[1]:" ")."</td><td>".($_from_h[1]?"$p_h[1] %":" ")."</td>"; }
  9860.             print "</tr>\n";
  9861.             &tab_end();
  9862.         }
  9863.     
  9864.         print "\n<a name=\"keys\"> </a>\n\n";
  9865.     
  9866.         # BY SEARCH KEYWORDS AND/OR KEYPHRASES
  9867.         #-------------------------------------
  9868.         if ($ShowKeyphrasesStats) { print "$Center<a name=\"keyphrases\"> </a>"; }
  9869.         if ($ShowKeywordsStats)   {    print "$Center<a name=\"keywords\"> </a>"; }
  9870.         if ($ShowKeyphrasesStats || $ShowKeywordsStats) { print "<br />\n"; }
  9871.         if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\"><tr>"; }
  9872.         if ($ShowKeyphrasesStats) {
  9873.             # By Keyphrases
  9874.             if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "<td width=\"50%\" valign=\"top\">\n";    }
  9875.             if ($Debug) { debug("ShowKeyphrasesStats",2); }
  9876.             &tab_head("$Message[120] ($Message[77] $MaxNbOf{'KeyphrasesShown'})<br /><a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=keyphrases"):"$PROG$StaticLinks.keyphrases.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>",19,($ShowKeyphrasesStats && $ShowKeywordsStats)?95:70,'keyphrases');
  9877.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(15)."><th>$TotalDifferentKeyphrases $Message[103]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[14]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[15]</th></tr>\n";
  9878.             $total_s=0;
  9879.             my $count=0;
  9880.             &BuildKeyList($MaxNbOf{'KeyphrasesShown'},$MinHit{'Keyphrase'},\%_keyphrases,\%_keyphrases);
  9881.             foreach my $key (@keylist) {
  9882.                 my $mot;
  9883.                 # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
  9884.                 if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'})  { $mot=CleanFromCSSA(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); }
  9885.                 else { $mot = CleanFromCSSA(DecodeEncodedString($key)); }
  9886.                 my $p;
  9887.                 if ($TotalKeyphrases) { $p=int($_keyphrases{$key}/$TotalKeyphrases*1000)/10; }
  9888.                 print "<tr><td class=\"aws\">".XMLEncode($mot)."</td><td>$_keyphrases{$key}</td><td>$p %</td></tr>\n";
  9889.                 $total_s += $_keyphrases{$key};
  9890.                 $count++;
  9891.             }
  9892.             if ($Debug) { debug("Total real / shown : $TotalKeyphrases / $total_s",2); }
  9893.             $rest_s=$TotalKeyphrases-$total_s;
  9894.             if ($rest_s > 0) {
  9895.                 my $p;
  9896.                 if ($TotalKeyphrases) { $p=int($rest_s/$TotalKeyphrases*1000)/10; }
  9897.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[124]</span></td><td>$rest_s</td>";
  9898.                 print "<td>$p %</td></tr>\n";
  9899.             }
  9900.             &tab_end();
  9901.             if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "</td>\n";    }
  9902.         }
  9903.         if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "<td>   </td>"; }
  9904.         if ($ShowKeywordsStats) {
  9905.             # By Keywords
  9906.             if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "<td width=\"50%\" valign=\"top\">\n";    }
  9907.             if ($Debug) { debug("ShowKeywordsStats",2); }
  9908.             &tab_head("$Message[121] ($Message[77] $MaxNbOf{'KeywordsShown'})<br /><a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=keywords"):"$PROG$StaticLinks.keywords.$StaticExt")."\"$NewLinkTarget>$Message[80]</a>",19,($ShowKeyphrasesStats && $ShowKeywordsStats)?95:70,'keywords');
  9909.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"".Tooltip(15)."><th>$TotalDifferentKeywords $Message[13]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[14]</th><th bgcolor=\"#$color_s\" width=\"80\">$Message[15]</th></tr>\n";
  9910.             $total_s=0;
  9911.             my $count=0;
  9912.             &BuildKeyList($MaxNbOf{'KeywordsShown'},$MinHit{'Keyword'},\%_keywords,\%_keywords);
  9913.             foreach my $key (@keylist) {
  9914.                 my $mot;
  9915.                 # Convert coded keywords (utf8,...) to be correctly reported in HTML page.
  9916.                 if ($PluginsLoaded{'DecodeKey'}{'decodeutfkeys'})  { $mot=CleanFromCSSA(DecodeKey_decodeutfkeys($key,$PageCode||'iso-8859-1')); }
  9917.                 else { $mot = CleanFromCSSA(DecodeEncodedString($key)); }
  9918.                 my $p;
  9919.                 if ($TotalKeywords) { $p=int($_keywords{$key}/$TotalKeywords*1000)/10; }
  9920.                 print "<tr><td class=\"aws\">".XMLEncode($mot)."</td><td>$_keywords{$key}</td><td>$p %</td></tr>\n";
  9921.                 $total_s += $_keywords{$key};
  9922.                 $count++;
  9923.             }
  9924.             if ($Debug) { debug("Total real / shown : $TotalKeywords / $total_s",2); }
  9925.             $rest_s=$TotalKeywords-$total_s;
  9926.             if ($rest_s > 0) {
  9927.                 my $p;
  9928.                 if ($TotalKeywords) { $p=int($rest_s/$TotalKeywords*1000)/10; }
  9929.                 print "<tr><td class=\"aws\"><span style=\"color: #$color_other\">$Message[30]</span></td><td>$rest_s</td>";
  9930.                 print "<td>$p %</td></tr>\n";
  9931.             }
  9932.             &tab_end();
  9933.             if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "</td>\n";    }
  9934.         }
  9935.         if ($ShowKeyphrasesStats && $ShowKeywordsStats) { print "</tr></table>\n"; }
  9936.     
  9937.         print "\n<a name=\"other\"> </a>\n\n";
  9938.     
  9939.         # BY MISC
  9940.         #----------------------------
  9941.         if ($ShowMiscStats) {
  9942.             if ($Debug) { debug("ShowMiscStats",2); }
  9943.             print "$Center<a name=\"misc\"> </a><br />\n";
  9944.             my $Totalh=0; my %new_browser_h=();
  9945.             if ($_misc_h{'AddToFavourites'}) {
  9946.                 foreach my $key (keys %_browser_h) {
  9947.                     $Totalh+=$_browser_h{$key};
  9948.                     if ($key =~ /^msie/i) { $new_browser_h{"msiecumul"}+=$_browser_h{$key}; }
  9949.                 }
  9950.                 if ($new_browser_h{'msiecumul'}) { $_misc_h{'AddToFavourites'}=int(0.5+$_misc_h{'AddToFavourites'}*$Totalh/$new_browser_h{'msiecumul'}); }
  9951.             }
  9952.             my $title="$Message[139]";
  9953.             &tab_head("$title",19,0,'misc');
  9954.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th>$Message[139]</th>";
  9955.             print "<th width=\"100\"> </th>";
  9956.             print "<th width=\"100\"> </th>";
  9957.             print "</tr>\n";
  9958.             my %label=('AddToFavourites'=>$Message[137],'JavaEnabled'=>$Message[140],'DirectorSupport'=>$Message[141],
  9959.             'FlashSupport'=>$Message[142],'RealPlayerSupport'=>$Message[143],'QuickTimeSupport'=>$Message[144],
  9960.             'WindowsMediaPlayerSupport'=>$Message[145],'PDFSupport'=>$Message[146]);
  9961.             foreach my $key (@MiscListOrder) {
  9962.                 my $mischar=substr($key,0,1);
  9963.                 if ($ShowMiscStats !~ /$mischar/i) { next; }
  9964.                 my $total=0;
  9965.                 my $p;
  9966.                 if ($MiscListCalc{$key} eq 'v') { $total=$TotalVisits; }
  9967.                 if ($MiscListCalc{$key} eq 'u') { $total=$TotalUnique; }
  9968.                 if ($MiscListCalc{$key} eq 'hm') { $total=$_misc_h{'TotalMisc'}||0; }
  9969.                 if ($total) { $p=int($_misc_h{$key}/$total*1000)/10; }
  9970.                 print "<tr>";
  9971.                 print "<td class=\"aws\">".($PageDir eq 'rtl'?"<span dir=\"ltr\">":"").$label{$key}.($PageDir eq 'rtl'?"</span>":"")."</td>";
  9972.                 if ($MiscListCalc{$key} eq 'v') { print "<td>".($_misc_h{$key}||0)." / $total $Message[12]</td>"; }
  9973.                 if ($MiscListCalc{$key} eq 'u') { print "<td>".($_misc_h{$key}||0)." / $total $Message[18]</td>"; }
  9974.                 if ($MiscListCalc{$key} eq 'hm') { print "<td>-</td>"; }
  9975.                 print "<td>".($total?"$p %":" ")."</td>";
  9976.                 print "</tr>\n";
  9977.             }
  9978.             &tab_end();
  9979.         }
  9980.     
  9981.         # BY HTTP STATUS
  9982.         #----------------------------
  9983.         if ($ShowHTTPErrorsStats) {
  9984.             if ($Debug) { debug("ShowHTTPErrorsStats",2); }
  9985.             print "$Center<a name=\"errors\"> </a><br />\n";
  9986.             my $title="$Message[32]";
  9987.             &tab_head("$title",19,0,'errors');
  9988.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"2\">$Message[32]*</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th><th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th></tr>\n";
  9989.             $total_h=0;
  9990.             my $count=0;
  9991.             &BuildKeyList($MaxRowsInHTMLOutput,1,\%_errors_h,\%_errors_h);
  9992.             foreach my $key (@keylist) {
  9993.                 my $p=int($_errors_h{$key}/$TotalHitsErrors*1000)/10;
  9994.                 print "<tr".Tooltip($key,$key).">";
  9995.                 if ($TrapInfosForHTTPErrorCodes{$key}) { print "<td><a href=\"".($ENV{'GATEWAY_INTERFACE'} || !$StaticLinks?XMLEncode("$AWScript?${NewLinkParams}output=errors$key"):"$PROG$StaticLinks.errors$key.$StaticExt")."\"$NewLinkTarget>$key</a></td>"; }
  9996.                 else { print "<td valign=\"top\">$key</td>"; }
  9997.                 print "<td class=\"aws\">".($httpcodelib{$key}?$httpcodelib{$key}:'Unknown error')."</td><td>$_errors_h{$key}</td><td>$p %</td><td>".Format_Bytes($_errors_k{$key})."</td>";
  9998.                 print "</tr>\n";
  9999.                 $total_h+=$_errors_h{$key};
  10000.                 $count++;
  10001.             }
  10002.             &tab_end("* $Message[154]");
  10003.         }
  10004.  
  10005.         # BY SMTP STATUS
  10006.         #----------------------------
  10007.         if ($ShowSMTPErrorsStats) {
  10008.             if ($Debug) { debug("ShowSMTPErrorsStats",2); }
  10009.             print "$Center<a name=\"errors\"> </a><br />\n";
  10010.             my $title="$Message[147]";
  10011.             &tab_head("$title",19,0,'errors');
  10012.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"2\">$Message[147]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th><th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th></tr>\n";
  10013.             $total_h=0;
  10014.             my $count=0;
  10015.             &BuildKeyList($MaxRowsInHTMLOutput,1,\%_errors_h,\%_errors_h);
  10016.             foreach my $key (@keylist) {
  10017.                 my $p=int($_errors_h{$key}/$TotalHitsErrors*1000)/10;
  10018.                 print "<tr".Tooltip($key,$key).">";
  10019.                 print "<td valign=\"top\">$key</td>";
  10020.                 print "<td class=\"aws\">".($smtpcodelib{$key}?$smtpcodelib{$key}:'Unknown error')."</td><td>$_errors_h{$key}</td><td>$p %</td><td>".Format_Bytes($_errors_k{$key})."</td>";
  10021.                 print "</tr>\n";
  10022.                 $total_h+=$_errors_h{$key};
  10023.                 $count++;
  10024.             }
  10025.             &tab_end();
  10026.         }
  10027.     
  10028.         # BY CLUSTER
  10029.         #----------------------------
  10030.         if ($ShowClusterStats) {
  10031.             if ($Debug) { debug("ShowClusterStats",2); }
  10032.             print "$Center<a name=\"clusters\"> </a><br />\n";
  10033.             my $title="$Message[155]";
  10034.             &tab_head("$title",19,0,'clusters');
  10035.             print "<tr bgcolor=\"#$color_TableBGRowTitle\"><th colspan=\"2\">$Message[155]</th>";
  10036.             if ($ShowClusterStats =~ /P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th><th bgcolor=\"#$color_p\" width=\"80\">$Message[15]</th>"; }
  10037.             if ($ShowClusterStats =~ /H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th><th bgcolor=\"#$color_h\" width=\"80\">$Message[15]</th>"; }
  10038.             if ($ShowClusterStats =~ /B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th><th bgcolor=\"#$color_k\" width=\"80\">$Message[15]</th>"; }
  10039.             print "</tr>\n";
  10040.             $total_p=$total_h=$total_k=0;
  10041.             # Cluster feature might have been enable in middle of month so we recalculate
  10042.             # total for cluster section only, to calculate ratio, instead of using global total
  10043.             foreach my $key (keys %_cluster_h) {
  10044.                 $total_p+=int($_cluster_p{$key}||0);
  10045.                 $total_h+=int($_cluster_h{$key}||0);
  10046.                 $total_k+=int($_cluster_k{$key}||0);
  10047.             }
  10048.             my $count=0;
  10049.             foreach my $key (keys %_cluster_h) {
  10050.                 my $p_p=int($_cluster_p{$key}/$total_p*1000)/10;
  10051.                 my $p_h=int($_cluster_h{$key}/$total_h*1000)/10;
  10052.                 my $p_k=int($_cluster_k{$key}/$total_k*1000)/10;
  10053.                 print "<tr>";
  10054.                 print "<td class=\"aws\" colspan=\"2\">Computer $key</td>";
  10055.                 if ($ShowClusterStats =~ /P/i) { print "<td>".($_cluster_p{$key}?$_cluster_p{$key}:" ")."</td><td>$p_p %</td>"; }
  10056.                 if ($ShowClusterStats =~ /H/i) { print "<td>$_cluster_h{$key}</td><td>$p_h %</td>"; }
  10057.                 if ($ShowClusterStats =~ /B/i) { print "<td>".Format_Bytes($_cluster_k{$key})."</td><td>$p_k %</td>"; }
  10058.                 print "</tr>\n";
  10059.                 $count++;
  10060.             }
  10061.             &tab_end();
  10062.         }
  10063.  
  10064.          # BY EXTRA SECTIONS
  10065.          #----------------------------
  10066.          foreach my $extranum (1..@ExtraName-1) {
  10067.              if ($Debug) { debug("ExtraName$extranum",2); }
  10068.              print "$Center<a name=\"extra$extranum\"> </a><br />";
  10069.             my $title=$ExtraName[$extranum];
  10070.              &tab_head("$title",19,0,"extra$extranum");
  10071.              print "<tr bgcolor=\"#$color_TableBGRowTitle\">";
  10072.              print "<th>".$ExtraFirstColumnTitle[$extranum]."</th>";
  10073.              if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "<th bgcolor=\"#$color_p\" width=\"80\">$Message[56]</th>"; }
  10074.              if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "<th bgcolor=\"#$color_h\" width=\"80\">$Message[57]</th>"; }
  10075.              if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "<th bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>"; }
  10076.              if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "<th width=\"120\">$Message[9]</th>"; }
  10077.              print "</tr>\n";
  10078.              $total_p=$total_h=$total_k=0;
  10079.              #$max_h=1; foreach (values %_login_h) { if ($_ > $max_h) { $max_h = $_; } }
  10080.              #$max_k=1; foreach (values %_login_k) { if ($_ > $max_k) { $max_k = $_; } }
  10081.              my $count=0;
  10082.              if ($ExtraStatTypes[$extranum] =~ m/P/i) { 
  10083.                  &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_p'});
  10084.              }
  10085.              else {
  10086.                  &BuildKeyList($MaxNbOfExtra[$extranum],$MinHitExtra[$extranum],\%{'_section_' . $extranum . '_h'},\%{'_section_' . $extranum . '_h'});
  10087.              }
  10088.             foreach my $key (@keylist) {
  10089.                  my $firstcol = CleanFromCSSA(DecodeEncodedString($key));
  10090.                  $total_p+=${'_section_' . $extranum . '_p'}{$key};
  10091.                  $total_h+=${'_section_' . $extranum . '_h'}{$key};
  10092.                  $total_k+=${'_section_' . $extranum . '_k'}{$key};
  10093.                  print "<tr>";
  10094.                  printf("<td class=\"aws\">$ExtraFirstColumnFormat[$extranum]</td>", $firstcol, $firstcol, $firstcol, $firstcol, $firstcol);
  10095.                  if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "<td>" . ${'_section_' . $extranum . '_p'}{$key} . "</td>"; }
  10096.                  if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "<td>" . ${'_section_' . $extranum . '_h'}{$key} . "</td>"; }
  10097.                  if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "<td>" . Format_Bytes(${'_section_' . $extranum . '_k'}{$key}) . "</td>"; }
  10098.                  if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "<td>" . (${'_section_' . $extranum . '_l'}{$key}?Format_Date(${'_section_' . $extranum . '_l'}{$key},1):'-') . "</td>"; }
  10099.                  print "</tr>\n";
  10100.                  $count++;
  10101.             }
  10102.             if ($ExtraAddAverageRow[$extranum]) {
  10103.                  print "<tr>";
  10104.                  print "<td class=\"aws\"><b>$Message[96]</b></td>";
  10105.                  if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "<td>" . ($count?($total_p/$count):" ") . "</td>"; }
  10106.                  if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "<td>" . ($count?($total_h/$count):" ") . "</td>"; }
  10107.                  if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "<td>" . ($count?Format_Bytes($total_k/$count):" ") . "</td>"; }
  10108.                  if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "<td> </td>"; }
  10109.                  print "</tr>\n";
  10110.             }
  10111.             if ($ExtraAddSumRow[$extranum]) {
  10112.                  print "<tr>";
  10113.                  print "<td class=\"aws\"><b>$Message[102]</b></td>";
  10114.                  if ($ExtraStatTypes[$extranum] =~ m/P/i) { print "<td>" . ($total_p) . "</td>"; }
  10115.                  if ($ExtraStatTypes[$extranum] =~ m/H/i) { print "<td>" . ($total_h) . "</td>"; }
  10116.                  if ($ExtraStatTypes[$extranum] =~ m/B/i) { print "<td>" . Format_Bytes($total_k) . "</td>"; }
  10117.                  if ($ExtraStatTypes[$extranum] =~ m/L/i) { print "<td> </td>"; }
  10118.                  print "</tr>\n";
  10119.             }
  10120.              &tab_end();
  10121.          }
  10122.     
  10123.         &html_end(1);
  10124.     }
  10125. }
  10126. else {
  10127.     print "Jumped lines in file: $lastlinenb\n";
  10128.     if ($lastlinenb) { print " Found $lastlinenb already parsed records.\n"; }
  10129.     print "Parsed lines in file: $NbOfLinesParsed\n";
  10130.     print " Found $NbOfLinesDropped dropped records,\n";
  10131.     print " Found $NbOfLinesCorrupted corrupted records,\n";
  10132.     print " Found $NbOfOldLines old records,\n";
  10133.     print " Found $NbOfNewLines new qualified records.\n";
  10134. }
  10135.  
  10136. #sleep 10;
  10137.  
  10138. 0;    # Do not remove this line
  10139.  
  10140.  
  10141. #-------------------------------------------------------
  10142. # ALGORITHM SUMMARY
  10143. #
  10144. # Read_Config();
  10145. # Check_Config() and Init variables
  10146. # if 'frame not index'
  10147. #    &Read_Language_Data($Lang);
  10148. #    if 'frame not mainleft'
  10149. #        &Read_Ref_Data();
  10150. #        &Read_Plugins();
  10151. # html_head
  10152. #
  10153. # If 'migrate'
  10154. #   We create/update tmp file with
  10155. #     &Read_History_With_TmpUpdate(year,month,UPDATE,NOPURGE,"all");
  10156. #   Rename the tmp file
  10157. #   html_end
  10158. #   Exit
  10159. # End of 'migrate'
  10160. #
  10161. # Get last history file name
  10162. # Get value for $LastLine $LastLineNumber $LastLineOffset $LastLineChecksum with
  10163. #    &Read_History_With_TmpUpdate(lastyear,lastmonth,NOUPDATE,NOPURGE,"general");
  10164. #
  10165. # &Init_HashArray()
  10166. #
  10167. # If 'update'
  10168. #   Loop on each new line in log file
  10169. #     lastlineoffset=lastlineoffsetnext; lastlineoffsetnext=file pointer position
  10170. #     If line corrupted, skip --> next on loop
  10171. #      Drop wrong virtual host --> next on loop
  10172. #     Drop wrong method/protocol --> next on loop
  10173. #     Check date --> next on loop
  10174. #     If line older than $LastLine, skip --> next on loop
  10175. #     So it's new line
  10176. #     $LastLine = time or record
  10177. #     Skip if url is /robots.txt --> next on loop
  10178. #     Skip line for @SkipHosts --> next on loop
  10179. #     Skip line for @SkipFiles --> next on loop
  10180. #     Skip line for @SkipUserAgent --> next on loop
  10181. #     Skip line for not @OnlyHosts --> next on loop
  10182. #     Skip line for not @OnlyFiles --> next on loop
  10183. #     Skip line for not @OnlyUserAgent --> next on loop
  10184. #     So it's new line approved
  10185. #     If other month/year, create/update tmp file and purge data arrays with
  10186. #       &Read_History_With_TmpUpdate(lastprocessedyear,lastprocessedmonth,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_));
  10187. #     Define a clean Url and Query (set urlwithnoquery, tokenquery and standalonequery and $field[$pos_url])
  10188. #     Define PageBool and extension
  10189. #     Analyze: Misc tracker --> complete %misc
  10190. #     Analyze: Add to favorites --> complete %_misc, countedtraffic=1 (not counted anywhere)
  10191. #     If (!countedtraffic) Analyze: Worms --> complete %_worms, countedtraffic=1
  10192. #     If (!countedtraffic) Analyze: Status code --> complete %_error_, %_sider404, %_referrer404 --> countedtraffic=1
  10193. #     If (!countedtraffic) Analyze: Robots known --> complete %_robot, countedtraffic=1
  10194. #     If (!countedtraffic) Analyze: Robots unknown on robots.txt --> complete %_robot, countedtraffic=1
  10195. #     If (!countedtraffic) Analyze: File types - Compression
  10196. #     If (!countedtraffic) Analyze: Date - Hour - Pages - Hits - Kilo
  10197. #     If (!countedtraffic) Analyze: Login
  10198. #     If (!countedtraffic) Do DNS Lookup
  10199. #     If (!countedtraffic) Analyze: Country
  10200. #     If (!countedtraffic) Analyze: Host - Url - Session
  10201. #     If (!countedtraffic) Analyze: Browser - OS
  10202. #     If (!countedtraffic) Analyze: Referer
  10203. #     If (!countedtraffic) Analyze: EMail
  10204. #     Analyze: Cluster
  10205. #     Analyze: Extra (must be after 'Define a clean Url and Query')
  10206. #     If too many records, we flush data arrays with
  10207. #       &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_));
  10208. #   End of loop
  10209. #   Create/update tmp file
  10210. #      Seek to lastlineoffset to read and get last line into $_ 
  10211. #      &Read_History_With_TmpUpdate($lastprocessedyear,$lastprocessedmonth,UPDATE,PURGE,"all",lastlinenb,lastlineoffset,CheckSum($_))
  10212. #   Rename all tmp files
  10213. # End of 'update'
  10214. #
  10215. # &Init_HashArray()
  10216. #
  10217. # If 'output'
  10218. #   Loop for each month of required year
  10219. #     &Read_History_With_TmpUpdate($YearRequired,monthloop,NOUPDATE,NOPURGE,"all" or "general time" if not required month)
  10220. #   End of loop
  10221. #   Show data arrays in HTML page
  10222. #   html_end
  10223. # End of 'output'
  10224. #-------------------------------------------------------
  10225.  
  10226. #-------------------------------------------------------
  10227. # DNS CACHE FILE FORMATS SUPPORTED BY AWSTATS
  10228. # Format /etc/hosts     x.y.z.w hostname
  10229. # Format analog         UT/60 x.y.z.w hostname
  10230. #-------------------------------------------------------
  10231.  
  10232. #-------------------------------------------------------
  10233. # IP Format (d=decimal on 16 bits, x=hexadecimal on 16 bits)
  10234. #
  10235. # 13.1.68.3                        IPv4 (d.d.d.d)
  10236. # 0:0:0:0:0:0:13.1.68.3         IPv6 (x:x:x:x:x:x:d.d.d.d)
  10237. # ::13.1.68.3
  10238. # 0:0:0:0:0:FFFF:13.1.68.3         IPv6 (x:x:x:x:x:x:d.d.d.d)
  10239. # ::FFFF:13.1.68.3                 IPv6
  10240. #
  10241. # 1070:0:0:0:0:800:200C:417B     IPv6
  10242. # 1070:0:0:0:0:800:200C:417B     IPv6
  10243. # 1070::800:200C:417B             IPv6
  10244. #-------------------------------------------------------
  10245.