home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / getstats.zip / GETSTATS.12.C < prev    next >
C/C++ Source or Header  |  1995-04-11  |  118KB  |  4,889 lines

  1. /*
  2. ** getstats 1.2
  3. **
  4. ** 4/16/94 Kevin Hughes, kevinh@eit.com
  5. ** All suggestions, help, etc. gratefully accepted.
  6. ** Get the latest version and documentation info at
  7. **     http://www.eit.com/software/getstats/getstats.html
  8. **     ftp://ftp.eit.com/pub/web.software/getstats/
  9. **
  10. ** Type "getstats -z" for command-line options.
  11. ** Change user defaults below before compiling!
  12. ** Compiles fine with gcc. Try "gcc getstats.c -o getstats".
  13. ** The version history is at the end of this source.
  14. **
  15. ** Thanks to Dan Riley, John Franks, Daniel Simmons, H. Morrow Long,
  16. ** Bill Hefley, Mark Donszelmann, Willem van Leeuwen, Tim Evans,
  17. ** James Pitkow, Eric Hagberg, Bruce O'Neel, Danny Mayer, Jeffry Abramson,
  18. ** and many more for contributing fixes and improvements!
  19. **
  20. ** Acknowledgements to Roy Fielding (wwwstat, fielding@simplon.ics.uci.edu)
  21. ** and Eric Katz (WebReport, ekatz@ncsa.uiuc.edu) for good ideas.
  22. */
  23.  
  24. /** User-defined defaults. Change to your liking! **/
  25.  
  26. #ifndef SERVERSITE
  27. #define SERVERSITE "http://www.eit.com/"
  28. #endif
  29.     /* The URL of your http server. Put a slash at the end!
  30.     */
  31. #ifndef ROOTDIR
  32. #define ROOTDIR "/usr/local/www"
  33. #endif
  34.     /* Overridden by -dr option.
  35.     ** The top of your Web/Gopher directory. Comment out this line if
  36.     ** you have no existing directory.
  37.     */
  38. #ifndef HOMEPAGE
  39. #define HOMEPAGE "/eit.home.html"
  40. #endif
  41.     /* The file to refer to when a request is "/" or empty.
  42.     ** Make sure a slash is at the beginning of this string.
  43.     */
  44. #ifndef LOGFILE
  45. #define LOGFILE "/usr/local/etc/httpd/logs/access_log"
  46. #endif
  47.     /* Overridden by -l option.
  48.     ** The httpd log file you want to analyze.
  49.     */
  50. #ifndef HTMLTITLE
  51. #define HTMLTITLE "Web Server Statistics"
  52. #endif
  53.     /* The default title for getstats HTML pages.
  54.     */
  55. #ifndef SERVERTYPE
  56. #define SERVERTYPE "NCSA"
  57. #endif
  58.     /* Overridden by -C, -N, -P, -G, -A, and -O options.
  59.     ** Default server type and format to use. Currently can be either
  60.     ** "CERN", "NCSA", "PLEXUS", "GN", "MAC", or "GOPHER".
  61.     */
  62. #ifndef COMMON
  63. #define COMMON 0
  64. #endif
  65.     /* Overridden by -M option.
  66.     ** If your log file is in the "common" format, define COMMON as
  67.     ** 1, else as 0.
  68.     */
  69. #ifndef CGI
  70. /* #define CGI */
  71. #endif
  72.     /* If you're using getstats as a CGI script, this will tell your
  73.     ** browser to expect the output to be HTML.
  74.     */
  75. #ifndef GMTOFFSET
  76. /* #define GMTOFFSET -28800 */
  77. #endif
  78.     /* Define this to be the difference in seconds between
  79.     ** the time as reported in the log file and your local time.
  80.     ** For example, if the log GMT time is 5 pm and your local time is
  81.     ** 2 pm, enter -10800 for the value. If the difference is 0,
  82.     ** or you wish to report all dates as they are in the log file,
  83.     ** comment out this line.
  84.     */
  85. #ifndef LOGTZ
  86. #define LOGTZ "local"
  87. #endif
  88.     /* Define this to be the time zone the log reports in.
  89.     ** For instance, "GMT", "local", "PST", etc. This is used only if
  90.     ** GMTOFFSET is not defined.
  91.     */
  92. #ifndef TOPLINES
  93. #define TOPLINES 0
  94. #endif
  95.     /* Overridden by -t option.
  96.     ** Define as the number of top lines to report in full, domain,
  97.     ** and request reports. Define as 0 to show all lines.
  98.     */
  99. #ifndef DOMAINFILE
  100. #define DOMAINFILE NULL
  101. #endif
  102.     /* Overridden by -df option.
  103.     ** The file to lookup domain code descriptions from.
  104.     ** Each line should be in the form "xx description..."
  105.     ** such as "COM Corporate site". Define as NULL if not needed.
  106.     */
  107. #ifndef ERRORREPORT
  108. #define ERRORREPORT "NONE"
  109. #endif
  110.     /* Overridden by -e option.
  111.     ** This will generate a report of malformed requests. Define as
  112.     ** "NONE" for no report, "YES" to add a report to standard
  113.     ** output, or a file name to append errors to an error log.
  114.     */
  115. #ifndef CONCISEREPORT
  116. #define CONCISEREPORT "NONE"
  117. #endif
  118.     /* Overridden by -c option.
  119.     ** This will generate only a paragraph of statistics.
  120.     ** Define as "YES" if you want it or "NONE" if not.
  121.     */
  122. #ifndef MONTHLYREPORT
  123. #define MONTHLYREPORT "NONE"
  124. #endif
  125.     /* Overridden by -m option.
  126.     ** This will add a monthly report to getstats output.
  127.     ** Define as "YES" if you want it or "NONE" if not.
  128.     */
  129. #ifndef WEEKLYREPORT
  130. #define WEEKLYREPORT "NONE"
  131. #endif
  132.     /* Overridden by -w option.
  133.     ** This will add a weekly report to getstats output.
  134.     ** Define as "YES" if you want it or "NONE" if not.
  135.     */
  136. #ifndef DAILYREPORT
  137. #define DAILYREPORT "NONE"
  138. #endif
  139.     /* Overridden by -d option.
  140.     ** This will add a daily report to getstats output.
  141.     ** Define as "YES" if you want it or "NONE" if not.
  142.     */
  143. #ifndef HOURLYREPORT
  144. #define HOURLYREPORT "NONE"
  145. #endif
  146.     /* Overridden by -h option.
  147.     ** This will add an hourly report to getstats output.
  148.     ** Define as "YES" if you want it or "NONE" if not.
  149.     */
  150. #ifndef DAYSUMREPORT
  151. #define DAYSUMREPORT "NONE"
  152. #endif
  153.     /* Overridden by -ds option.
  154.     ** This will add a daily summary report to getstats output.
  155.     ** Define as "YES" if you want it or "NONE" if not.
  156.     */
  157. #ifndef HOURSUMREPORT
  158. #define HOURSUMREPORT "NONE"
  159. #endif
  160.     /* Overridden by -hs option.
  161.     ** This will add an hourly summary report to getstats output.
  162.     ** Define as "YES" if you want it or "NONE" if not.
  163.     */
  164. #ifndef FULLREPORT
  165. #define FULLREPORT "NONE"
  166. #endif
  167.     /* Overridden by -f, -fa, -fd, and -fb options.
  168.     ** This will add a full report to getstats output. This can be
  169.     ** "FULLADDR" (sorted by address), "FULLACCESS" (sorted by accesses),
  170.     ** "FULLDATE" (sorted by access date), or "FULLBYTES" (sorted by
  171.     **  byte traffic per site). Define as "NONE" if you don't want it.
  172.     */
  173. #ifndef REQUESTREPORT
  174. #define REQUESTREPORT "NONE"
  175. #endif
  176.     /* Overridden by -r, -ra, -rd, -rb, and -rf options.
  177.     ** The default request report getstats generates. This can be
  178.     ** "REQUEST" (sorted by request), "REQACCESS" (sorted by accesses),
  179.     ** "REQDATE" (sorted by date), "REQBYTES" (sorted by byte
  180.     ** traffic per request), or "REQFILE" (sorted by individual
  181.     ** filesizes). Define as "NONE" if you don't want this report
  182.     ** added to your output automatically.
  183.     */
  184. #ifndef DOMAINREPORT
  185. #define DOMAINREPORT "NONE"
  186. #endif
  187.     /* Overridden by -dn, -da, -dd, and -db options.
  188.     ** The default domain report getstats generates. This can be
  189.     ** "DOMAIN" (sorted by domain), "DOMACCESS" (sorted by accesses),
  190.     ** "DOMDATE" (sorted by date), "DOMBYTES" (sorted by byte
  191.     ** traffic per domain), or "DOMUNIQ" (sorted by number of unique
  192.     ** domains). Define as "NONE" if you don't want this report added
  193.     ** to your output automatically.
  194.     */
  195. #ifndef TREEREPORT
  196. #define TREEREPORT "NONE"
  197. #endif
  198.     /* Overridden by -dt option.
  199.     ** If defined as "YES", generates a request report sorted
  200.     ** by the directory levels in your web tree. Define as "NONE"
  201.     ** to omit it. This report is not shown under VMS.
  202.     */
  203. #ifndef DOMAINLEVELS
  204. #define DOMAINLEVELS 1
  205. #endif
  206.     /* Overridden by -dl option.
  207.     ** The numbers of domain levels getstats analyzes. If this were
  208.     ** 2, the domain ".edu" and ".berkeley.edu" would be reported
  209.     ** for the address "ocf.berkeley.edu".
  210.     */
  211. #ifndef PRINTBYTES
  212. #define PRINTBYTES 0
  213. #endif
  214.     /* Overridden by -b option.
  215.     ** This will add byte traffic stats to all reports.
  216.     ** Define as 0 if not wanted.
  217.     */
  218. #ifndef PRINTHTML
  219. #define PRINTHTML 0
  220. #endif
  221.     /* Overridden by -ht option.
  222.     ** If defined as 1, getstats prints its reports in HTML.
  223.     ** Define as 0 if not wanted.
  224.     */
  225. #ifndef PRINTURLS
  226. /* #define PRINTURLS "pre" */
  227. #endif
  228.     /* If printing HTML request reports, this will make any
  229.     ** request entry into a URL, so you can click on it.
  230.     ** Specify the style of the report as well, such as "pre".
  231.     ** Comment out if not needed.
  232.     */
  233. #ifndef USEHTMLICON
  234. /* #define USEHTMLICON "getstats.gif" */
  235. #endif
  236.     /* If defined, this image will be shown in HTML report pages.
  237.     ** Uncomment if not wanted - the getstats logo is available
  238.     ** at the distribution FTP site (see above).
  239.     */
  240.  
  241. /* Beginning of string mask options */
  242.  
  243. /* For each of the following mask options, the following applies:
  244. **
  245. ** 1) You can use asterisks in specifying the string, at either
  246. **    ends of the string:
  247. **    "192.100.*", "*100*", "*.com", "*.html", "*cgi-bin*"
  248. ** 2) You can make lists of masks:
  249. **    "*eit.com,*.edu", "*.html,*cgi-bin*", ".58.2,*100"
  250. ** 3) A mask without asterisks will match EXACTLY:
  251. **    "ocf.berkeley.edu", "/pictures/faces.gif"
  252. ** 4) Define as "NONE" if you don't want a default.
  253. */
  254.  
  255. #ifndef ADDRMASK
  256. #define ADDRMASK "NONE"
  257. #endif
  258.     /* Overridden by -ss option. (string skip)
  259.     ** Name and IP addresses matching conditions in this string
  260.     ** WON'T be reported.
  261.     */
  262. #ifndef ADDRONLYMASK
  263. #define ADDRONLYMASK "NONE"
  264. #endif
  265.     /* Overridden by -sa option. (string address)
  266.     ** ONLY name and IP addresses matching conditions in this string
  267.     ** WILL be reported.
  268.     */
  269. #ifndef REQMASK
  270. #define REQMASK "NONE"
  271. #endif
  272.     /* Overridden by -sp option. (string skip)
  273.     ** Requests with this string in it WON'T be reported.
  274.     */
  275. #ifndef REQONLYMASK
  276. #define REQONLYMASK "NONE"
  277. #endif
  278.     /* Overridden by -sr option. (string request)
  279.     ** ONLY requests with this string in it WILL be reported.
  280.     */
  281.  
  282. /* End of string mask options */
  283.  
  284. #ifndef DATEMASK
  285. #define DATEMASK "ALLDATES"
  286. #endif
  287.     /* Overridden by -sd option. (string date)
  288.     ** ONLY requests matching the date conditions in the string WILL be
  289.     ** reported. Define as "ALLDATES" to report all dates. The format
  290.     ** must be in "m/d/y", although asterisks can be used as wildcards
  291.     ** in each field as well as ranges such as "1/[5-30]/[92-93]".
  292.     ** The string can also be specified as "today", "yesterday",
  293.     ** "lastweek", "thisweek", "thismonth", or "lastmonth".
  294.     */
  295. #ifndef HOURMASK
  296. #define HOURMASK "ALLHOURS"
  297. #endif
  298.     /* Overridden by -sh option. (string hour)
  299.     ** ONLY requests matching the hour conditions in the string WILL be
  300.     ** reported. Define as "ALLHOURS" to report all hours.
  301.     ** Examples: "1-23" (1 am to 11 pm), "9" (9 am only),
  302.     ** "-17" (midnight to 5 pm), "15-" (3 pm to midnight).
  303.     */
  304. #ifndef DAYMASK
  305. #define DAYMASK "ALLDAYS"
  306. #endif
  307.     /* Overridden by -sw option.
  308.     ** ONLY requests matching the day conditions in the string WILL be
  309.     ** reported. Define as "ALLDAYS" to report all days.
  310.     ** Examples: "mon", "Mon", or "MON" (Mondays only),
  311.     ** "mon-fri" (weekdays only), "wed-sun" (Wednesdays to Sundays only),
  312.     ** "mon-" (Mondays to Sundays), "-thu" (Mondays to Thursdays).
  313.     ** You can also specify the string as "weekends" or "weekdays".
  314.     */
  315. #ifndef MONTHMARK
  316. #define MONTHMARK 1000
  317. #endif
  318.     /* Number of files a mark represents in weekly statistics.
  319.     ** For larger servers, multiply this by 10.
  320.     */
  321. #ifndef WEEKMARK
  322. #define WEEKMARK 50
  323. #endif
  324.     /* Number of files a mark represents in weekly statistics.
  325.     ** For larger servers, multiply this by 10.
  326.     */
  327. #ifndef DAYMARK
  328. #define DAYMARK 10
  329. #endif
  330.     /* Number of files a mark represents in daily statistics.
  331.     ** For larger servers, multiply this by 10.
  332.     */
  333. #ifndef HOURMARK
  334. #define HOURMARK 2
  335. #endif
  336.     /* Number of files a mark represents in hourly statistics.
  337.     ** For larger servers, multiply this by 10.
  338.     */
  339. #ifndef MONTHBYTEMARK
  340. #define MONTHBYTEMARK (MONTHMARK * 10000)
  341. #endif
  342.     /* Number of bytes a mark represents in weekly statistics.
  343.     */
  344. #ifndef WEEKBYTEMARK
  345. #define WEEKBYTEMARK (WEEKMARK * 10000)
  346. #endif
  347.     /* Number of bytes a mark represents in weekly statistics.
  348.     */
  349. #ifndef DAYBYTEMARK
  350. #define DAYBYTEMARK (DAYMARK * 10000)
  351. #endif
  352.     /* Number of bytes a mark represents in daily statistics.
  353.     */
  354. #ifndef HOURBYTEMARK
  355. #define HOURBYTEMARK (HOURMARK * 10000)
  356. #endif
  357.     /* Number of bytes a mark represents in hourly statistics.
  358.     */
  359. #ifndef DAYSUMMARK
  360. #define DAYSUMMARK (DAYMARK * 10)
  361. #endif
  362.     /* Number of files a mark represents in daily summary statistics.
  363.     */
  364. #ifndef HOURSUMMARK
  365. #define HOURSUMMARK (HOURMARK * 10)
  366. #endif
  367.     /* Number of files a mark represents in hourly summary statistics.
  368.     */
  369. #ifndef DAYSUMBYTEMARK
  370. #define DAYSUMBYTEMARK (DAYSUMMARK * 10000)
  371. #endif
  372.     /* Number of bytes a mark represents in daily summary statistics.
  373.     */
  374. #ifndef HOURSUMBYTEMARK
  375. #define HOURSUMBYTEMARK (HOURSUMMARK * 10000)
  376. #endif
  377.     /* Number of bytes a mark represents in hourly summary statistics.
  378.     */
  379. #ifndef MARK
  380. #define MARK '#'
  381. #endif
  382.     /* What you want the file mark character to be.
  383.     */
  384. #ifndef BYTEMARK
  385. #define BYTEMARK '+'
  386. #endif
  387.     /* What you want the byte mark character to be.
  388.     */
  389. #ifndef LOOKUP
  390. #define LOOKUP "NO"
  391. #endif
  392.     /* Overridden by -ip option.
  393.     ** Define as "NO" if you want getstats to stop looking up names
  394.     ** for numerical addresses. This can save a lot of time!
  395.     ** Define as "YES" if you want lookup.
  396.     */
  397. #ifndef TRUNCATE
  398. #define TRUNCATE 80
  399. #endif
  400.     /* Define as 0 if you want getstats to not truncate to a
  401.     ** certain character length in graphs and the request report.
  402.     ** Otherwise, define as the length you want (such as 80).
  403.     */
  404. #ifndef SHOWTREEFILES
  405. /* #define SHOWTREEFILES */
  406. #endif
  407.     /* Defining this will show files as well as directories in
  408.     ** directory tree reports. Comment out the line if you only
  409.     ** wish to show directories.
  410.     */
  411. #ifndef SHOWIPDOMAINS
  412. /* #define SHOWIPDOMAINS */
  413. #endif
  414.     /* Defining this will show numerical IP domains in domain
  415.     ** reports. Comment out the line if you want to hide IP domains.
  416.     */
  417. #ifndef EURODATE
  418. /* #define EURODATE */
  419. #endif
  420.     /*
  421.     ** Define this if you'd like dates reported as "D/M/Y" and
  422.     ** not "M/D/Y". Comment out if you don't.
  423.     */
  424. #ifndef SHOWSECONDS
  425. /* #define SHOWSECONDS */
  426. #endif
  427.     /* Define this if you want getstats to add access time with
  428.     ** hour, minute, and seconds to non-graph reports.
  429.     ** Comment out the line if you don't.
  430.     */
  431. #ifndef GNREPORTALL
  432. /* #define GNREPORTALL */
  433. #endif
  434.     /* Define this if you want your GN server to report Gopher as well
  435.     ** as HTML requests. Comment out the line if you don't.
  436.     */
  437. #ifndef REPORTTAG
  438. #define REPORTTAG "listing"
  439. #endif
  440.     /* The style you want the reports to print out in. Usually
  441.     ** "listing" seems to work well, but can be small to read.
  442.     ** Try "pre" as well.
  443.     */
  444.  
  445. /** End of user-definable options **/
  446.  
  447. #define PROGNAME  "getstats"
  448. #define VERSION   "1.2"
  449. #define DOCURL    "http://www.eit.com/software/getstats/getstats.html"
  450. #define PLEXURL   "http://www.bsdi.com/server/doc/plexus.html"
  451. #define GNURL     "http://hopf.math.nwu.edu/"
  452. #define NCSAURL   "http://hoohoo.ncsa.uiuc.edu/docs/Overview.html"
  453. #define CERNURL   "http://info.cern.ch/hypertext/WWW/Daemon/User/Guide.html"
  454. #define MACURL    "http://www.uth.tmc.edu/mac_info/machttp_info.html"
  455. #define GOPHURL   "gopher://boombox.micro.umn.edu"
  456.  
  457. #define MAXLINE        1000
  458. #define HASHLINE       200
  459. #define ADDRLEN        80
  460. #define DATELEN        25
  461. #define MACDATELEN     18
  462. #define COMMONDATELEN  27
  463. #define REQUESTLEN     500
  464. #define DOMAINLEN      80
  465. #define DOMLEN         10
  466. #define DOMLINELEN     80
  467. #define DOMDESCLEN     40
  468. #define SERVERTYPELEN  10
  469. #define REPORTTYPELEN  80
  470. #define DIRLEN         80
  471. #define URLLEN         80
  472. #define MASKLEN        80
  473. #define FLAGLEN        5
  474. #define BREAKLEN       46
  475. #define LONGDATELEN    80
  476. #define SHORTDATELEN   9
  477. #define DATENOTZLEN    19
  478. #define TZLEN          3
  479. #define DATEARGLEN     10
  480. #define DAYSPERWEEK    7
  481. #define DAYSPERYEAR    365
  482. #define WEEKSPERYEAR   52
  483. #define HOURSPERDAY    24
  484. #define SECSPERMIN     60
  485. #define SECSPERHOUR    3600
  486. #define SECSPERDAY     86400
  487. #define SECSPERWEEK    SECSPERDAY * DAYSPERWEEK
  488. #define SECSPERYEAR    SECSPERWEEK * WEEKSPERYEAR
  489. #define CENTURY        1900
  490. #define CENTURYSTR     "1900"
  491. #define BASEYEAR       1970
  492. #define HASHSIZE       101
  493. #define PROGRESSLEN    40
  494. #define IPDOMSTR       "(numerical domains)"
  495. #define NOROOTDIR      "<nodir>"
  496.  
  497. #ifdef EURODATE
  498. #define DATEFORMAT "D/M/Y"
  499. #else
  500. #define DATEFORMAT "M/D/Y"
  501. #endif
  502.  
  503. #ifndef ROOTDIR
  504. #define ROOTDIR NOROOTDIR
  505. #endif
  506.  
  507. #define IS_LEAP(y) (y > 1752 && (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)))
  508.  
  509. #ifndef SYSV
  510. #ifdef VMS
  511.     extern noshare int h_errno;
  512. #else
  513.     extern int h_errno;
  514. #endif
  515. #endif
  516.  
  517. #include <stdio.h>
  518. #include <time.h>
  519. #include <limits.h>
  520.  
  521. #ifdef VMS
  522. #include <types.h>
  523. #include <stat.h>
  524. #include <socket.h>
  525. #include <in.h>
  526. #ifdef MULTINET
  527. #include "multinet_root:[multinet.include]netdb.h"
  528. #else
  529. #ifdef UCX
  530. #include <netdb.h>
  531. #endif
  532. #endif
  533. #include <ctype.h>
  534. #else
  535. #include <sys/types.h>
  536. #include <sys/stat.h>
  537. #include <sys/socket.h>
  538. #include <netinet/in.h>
  539. #include <netdb.h>
  540. #endif
  541.  
  542. struct entry {
  543.     char *address;
  544.     long date;
  545.     int docnum;
  546.     long filesize;
  547.     struct entry *left;
  548.     struct entry *right;
  549. } *list, *sortedlist;
  550.  
  551. struct requestentry {
  552.     char *request;
  553.     long date;
  554.     int requestnum;
  555.     long requestsize;
  556.     long filesize;
  557.     struct requestentry *left;
  558.     struct requestentry *right;
  559. } *requestlist, *sortedrequestlist, *treereqlist;
  560.  
  561. struct domainentry {
  562.     char *domain;
  563.     long date;
  564.     int requestnum;
  565.     long filesize;
  566.     int unique;
  567.     struct domainentry *left;
  568.     struct domainentry *right;
  569. } *domainlist, *sorteddomainlist;
  570.  
  571. struct hosttable {
  572.     char *numaddress;
  573.     char *nameaddress;
  574.     struct hosttable *next;
  575. };
  576.  
  577. struct sizetable {
  578.     long filesize;
  579.     char *request;
  580.     struct sizetable *next;
  581. };
  582.  
  583. struct requesttable {
  584.     char *request;
  585.     long date;
  586.     long filesize;
  587.     int requestnum;
  588.     int removed;
  589.     struct requesttable *next;
  590. };
  591.  
  592. struct domaintable {
  593.     char *domain;
  594.     char *description;
  595.     struct domaintable *next;
  596. };
  597.  
  598. struct dnametable {
  599.     char *domain;
  600.     struct dnametable *next;
  601. };
  602.  
  603. struct node {
  604.     char *shortdate;
  605.     int requests;
  606.     int hour;
  607.     int total;
  608.     long filesize;
  609.     struct node *next;
  610. } *monthlyreport, *weeklyreport, *dailyreport, *hourlyreport;
  611.  
  612. struct errorlist {
  613.     char *error;
  614.     struct errorlist *next;
  615. } *errorreport;
  616.  
  617. char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
  618.     "Sep", "Oct", "Nov", "Dec" };
  619. char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  620. int monthdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 30, 30, 31 };
  621.  
  622. int checkfiles, printhtml, printbytes;
  623. long hoursumstats[48], daysumstats[14];
  624. char *domainfile, full_report[REPORTTYPELEN], request_report[REPORTTYPELEN],
  625.     domain_report[REPORTTYPELEN], server_url[URLLEN], rootdir[DIRLEN];
  626. static int largestdocnum, largestreqnum, largestdomnum, largestudomnum,
  627.     uniquehostnum, uniquedomnum, uniquereqnum, lastweekshosts,
  628.     loglines, toplines, linespermark, largetreereqnum, largetreebytenum;
  629. static long largestmonthnum, largestweeknum, largestdaynum, largesthournum,
  630.     largestbytenum, largestfilesizenum;
  631. static struct hosttable *addrtable[HASHSIZE];
  632. static struct sizetable *reqtable[HASHSIZE];
  633. static struct domaintable *domtable[HASHSIZE];
  634. static struct dnametable *dntable[HASHSIZE];
  635. static struct requesttable *treetable[HASHSIZE];
  636.  
  637. unsigned hash();
  638. struct entry *addentry();
  639. struct requestentry *addrequestentry();
  640. struct domainentry *adddomainentry();
  641. struct requestentry *addsortrequestentry();
  642. struct node *addnode();
  643. struct errorlist *adderror();
  644. char *getweekdatemask();
  645. int getcommondateaddress();
  646. int getcerndateaddress();
  647. int getncsadateaddress();
  648. int getplexdateaddress();
  649. int getgndateaddress();
  650. int getmacdateaddress();
  651. int getgophdateaddress();
  652. char *lookupnumaddr();
  653. void printgraph();
  654. void printfullheader();
  655. char *hashlookupnumaddr();
  656. char *getlocaltime();
  657. char *getshortdate();
  658. long getyearsecs();
  659. char *getdatestr();
  660. int isokdatechar();
  661. int numstrchr();
  662. long getsize();
  663. long isempty();
  664. long getthetime();
  665. void *emalloc();
  666. void fixslash();
  667. char *strdup();
  668. void usage();
  669. void progerr();
  670. void removespaces();
  671. void makelower();
  672. void parsedatemask();
  673. void parsehourmask();
  674. void parsedaymask();
  675. void setupprogress();
  676. void installdomaintable();
  677. void updateprogress();
  678. int isokhour();
  679. int isokday();
  680. void convtoshortdate();
  681. char *convtoeurodate();
  682. int isokdate();
  683. int isip();
  684. char *headerend();
  685. int isokstring();
  686. int ishtmlrequest();
  687. int isscriptrequest();
  688. void analyzemonthly();
  689. void analyzeweekly();
  690. void analyzedaysum();
  691. void analyzedaily();
  692. void analyzehoursum();
  693. void analyzehourly();
  694. int isinlastweek();
  695. int convtoyearsecs();
  696. void getdomain();
  697. void addtreeentry();
  698. void printerrors();
  699. void printheader();
  700. void printcovers();
  701. void printstats();
  702. void printdates();
  703. void printrunning();
  704. void noactivity();
  705. void printbottomhtml();
  706. void printmonthlyheader();
  707. void printweeklyheader();
  708. void printgraphreport();
  709. void printbreak();
  710. void printdaysumheader();
  711. void printsummary();
  712. void printdailyheader();
  713. void printhoursumheader();
  714. void printhourlyheader();
  715. void sortreport();
  716. int numlen();
  717. void printreport();
  718. void sortrequests();
  719. void printreqheader();
  720. void printrequests();
  721. void sortdomains();
  722. void printdomheader();
  723. void printdomains();
  724. void printtreeheader();
  725. void printtree();
  726. void printerrorheader();
  727. int daydifference();
  728. int getmondaynum();
  729. char *getmonth();
  730. int getweekday();
  731. int getyearday();
  732. void addhashreq();
  733. void addhashdn();
  734. void addhashdom();
  735. int addrcmp();
  736. int isdirectory();
  737. int isinname();
  738. int isnumber();
  739. void parsedaterange();
  740. int getday();
  741. int hashlookupdn();
  742. int isfile();
  743.  
  744. int main(argc, argv)
  745.      int argc;
  746.      char **argv;
  747. {
  748.     char c, d, *logfile;
  749.     char server_type[SERVERTYPELEN], tree_report[REPORTTYPELEN],
  750.         concise_report[REPORTTYPELEN], monthly_report[REPORTTYPELEN],
  751.         weekly_report[REPORTTYPELEN], daily_report[REPORTTYPELEN],
  752.         hourly_report[REPORTTYPELEN], daysum_report[REPORTTYPELEN],
  753.         hoursum_report[REPORTTYPELEN], error_report[REPORTTYPELEN],
  754.         lookup[FLAGLEN], logline[MAXLINE], request[REQUESTLEN],
  755.         address[ADDRLEN], addrmask[MASKLEN], addronlymask[MASKLEN],
  756.         datemask[MASKLEN], hourmask[MASKLEN], daymask[MASKLEN],
  757.         reqonlymask[MASKLEN], reqmask[MASKLEN],
  758.         date[DATELEN], firstdate[DATELEN], lastdate[DATELEN],
  759.         shortdate[SHORTDATELEN], newshortdate[SHORTDATELEN],
  760.         monthstr[DATEARGLEN], daystr[DATEARGLEN], yearstr[DATEARGLEN];
  761.     int i, use_stdin, docfieldlen, reqfieldlen, domfieldlen, bytefieldlen,
  762.         uniqfieldlen, sizefieldlen, islastweek, islastline,
  763.         isfirstline, domainlevels, highhour, lowhour, lowday, highday,
  764.         errors, allreports, showprogress, common;
  765.     static int htmldocnum, scriptnum, assetnum, lastweeksrequests;
  766.     long starttime, stoptime, nowtime, longdate, filesize, bytecount;
  767.     static struct tm *currenttime;
  768.     FILE *fp, *fperr;
  769.     int (*serverfunction) ();
  770.  
  771.     filesize = 0;
  772.     use_stdin = showprogress = allreports = bytecount = 0;
  773.     monthstr[0] = daystr[0] = yearstr[0] = '\0';
  774.     monthlyreport = weeklyreport = dailyreport = hourlyreport = NULL;
  775.     list = NULL;
  776.     requestlist = treereqlist = sortedrequestlist = NULL;
  777.     domainlist = sorteddomainlist = NULL;
  778.     common = COMMON;
  779.     domainlevels = DOMAINLEVELS;
  780.     toplines = TOPLINES;
  781.     printhtml = PRINTHTML;
  782.     printbytes = PRINTBYTES;
  783.     strcpy(lookup, LOOKUP);
  784.     strcpy(rootdir, ROOTDIR);
  785.     strcpy(server_type, SERVERTYPE);
  786.     strcpy(concise_report, CONCISEREPORT);
  787.     strcpy(monthly_report, MONTHLYREPORT);
  788.     strcpy(weekly_report, WEEKLYREPORT);
  789.     strcpy(daysum_report, DAYSUMREPORT);
  790.     strcpy(daily_report, DAILYREPORT);
  791.     strcpy(hoursum_report, HOURSUMREPORT);
  792.     strcpy(hourly_report, HOURLYREPORT);
  793.     strcpy(full_report, FULLREPORT);
  794.     strcpy(request_report, REQUESTREPORT);
  795.     strcpy(domain_report, DOMAINREPORT);
  796.     strcpy(tree_report, TREEREPORT);
  797.     strcpy(error_report, ERRORREPORT);
  798.     strcpy(datemask, DATEMASK);
  799.     strcpy(hourmask, HOURMASK);
  800.     strcpy(daymask, DAYMASK);
  801.     strcpy(reqmask, REQMASK);
  802.     strcpy(reqonlymask, REQONLYMASK);
  803.     strcpy(addrmask, ADDRMASK);
  804.     strcpy(addronlymask, ADDRONLYMASK);
  805.     logfile = LOGFILE;
  806.     domainfile = DOMAINFILE;
  807.  
  808.     while (--argc > 0) {
  809.         ++argv;
  810.         if ((*argv)[0] != '-')
  811.             usage();
  812.         c = (*argv)[1];
  813.         d = (*argv)[2];
  814.         if (c == 'a' && strlen(*argv) == 2)
  815.             allreports = 1;
  816.         else if (c == 'f' && strlen(*argv) == 2)
  817.             strcpy(full_report, "FULLADDR");
  818.         else if (c == 'f' && d == 'a')
  819.             strcpy(full_report, "FULLACCESS");
  820.         else if (c == 'f' && d == 'd')
  821.             strcpy(full_report, "FULLDATE");
  822.         else if (c == 'f' && d == 'b') {
  823.             strcpy(full_report, "FULLBYTES");
  824.             printbytes = 1;
  825.         }
  826.         else if (c == 'c' && strlen(*argv) == 2)
  827.             strcpy(concise_report, "YES");
  828.         else if (c == 'm' && strlen(*argv) == 2)
  829.             strcpy(monthly_report, "YES");
  830.         else if (c == 'w' && strlen(*argv) == 2)
  831.             strcpy(weekly_report, "YES");
  832.         else if (c == 'd' && strlen(*argv) == 2)
  833.             strcpy(daily_report, "YES");
  834.         else if (c == 'h' && strlen(*argv) == 2)
  835.             strcpy(hourly_report, "YES");
  836.         else if (c == 'd' && d =='s')
  837.             strcpy(daysum_report, "YES");
  838.         else if (c == 'h' && d == 's')
  839.             strcpy(hoursum_report, "YES");
  840.         else if (c == 'C' && strlen(*argv) == 2)
  841.             strcpy(server_type, "CERN");
  842.         else if (c == 'N' && strlen(*argv) == 2)
  843.             strcpy(server_type, "NCSA");
  844.         else if (c == 'P' && strlen(*argv) == 2)
  845.             strcpy(server_type, "PLEXUS");
  846.         else if (c == 'G' && strlen(*argv) == 2)
  847.             strcpy(server_type, "GN");
  848.         else if (c == 'A' && strlen(*argv) == 2)
  849.             strcpy(server_type, "MAC");
  850.         else if (c == 'O' && strlen(*argv) == 2)
  851.             strcpy(server_type, "GOPHER");
  852.         else if (c == 'M' && strlen(*argv) == 2)
  853.             common = 1;
  854.         else if (c == 'r' && strlen(*argv) == 2)
  855.             strcpy(request_report, "REQUEST");
  856.         else if (c == 'r' && d == 'a')
  857.             strcpy(request_report, "REQACCESS");
  858.         else if (c == 'r' && d == 'd')
  859.             strcpy(request_report, "REQDATE");
  860.         else if (c == 'r' && d == 'b') {
  861.             strcpy(request_report, "REQBYTES");
  862.             printbytes = 1;
  863.         }
  864.         else if (c == 'r' && d == 'f') {
  865.             strcpy(request_report, "REQFILE");
  866.             printbytes = 1;
  867.         }
  868.         else if (c == 'd' && d == 'n')
  869.             strcpy(domain_report, "DOMAIN");
  870.         else if (c == 'd' && d == 'a')
  871.             strcpy(domain_report, "DOMACCESS");
  872.         else if (c == 'd' && d == 'd')
  873.             strcpy(domain_report, "DOMDATE");
  874.         else if (c == 'd' && d == 'b') {
  875.             strcpy(domain_report, "DOMBYTES");
  876.             printbytes = 1;
  877.         }
  878.         else if (c == 'd' && d == 'u')
  879.             strcpy(domain_report, "DOMUNIQ");
  880.         else if (c == 'd' && d == 't')
  881.             strcpy(tree_report, "YES");
  882.         else if (c == 'd' && d == 'l') {
  883.             domainlevels = atoi((++argv)[0]);
  884.             argc--;
  885.         }
  886.         else if (c == 's' && d == 's') {
  887.             strcpy(addrmask, (++argv)[0]);
  888.             argc--;
  889.         }
  890.         else if (c == 's' && d == 'a') {
  891.             strcpy(addronlymask, (++argv)[0]);
  892.             argc--;
  893.         }
  894.         else if (c == 's' && d == 'p') {
  895.             strcpy(reqmask, (++argv)[0]);
  896.             argc--;
  897.         }
  898.         else if (c == 's' && d == 'r') {
  899.             strcpy(reqonlymask, (++argv)[0]);
  900.             argc--;
  901.         }
  902.         else if (c == 's' && d == 'd') {
  903.             strcpy(datemask, (++argv)[0]);
  904.             argc--;
  905.         }
  906.         else if (c == 's' && d == 'h') {
  907.             strcpy(hourmask, (++argv)[0]);
  908.             argc--;
  909.         }
  910.         else if (c == 's' && d == 'w') {
  911.             strcpy(daymask, (++argv)[0]);
  912.             argc--;
  913.         }
  914.         else if (c == 'i' && strlen(*argv) == 2)
  915.             use_stdin = 1;
  916.         else if (c == 'p' && strlen(*argv) == 2)
  917.             showprogress = 1;
  918.         else if (c == 'i' && d == 'p')
  919.             strcpy(lookup, "YES");
  920.         else if (c == 'h' && d == 't')
  921.             printhtml = 1;
  922.         else if (c == 'b' && strlen(*argv) == 2)
  923.             printbytes = 1;
  924.         else if (c == 'e' && strlen(*argv) == 2) {
  925.             if (argc - 2 == -1)
  926.                 strcpy(error_report, "YES");
  927.             else if ((*(argv + 1))[0] == '-')
  928.                 strcpy(error_report, "YES");
  929.             else {
  930.                 strcpy(error_report, (++argv)[0]);
  931.                 argc--;
  932.             }
  933.         }
  934.         else if (c == 'd' && d == 'r') {
  935.             if (argc - 2 == -1)
  936.                 strcpy(rootdir, NOROOTDIR);
  937.             else if ((*(argv + 1))[0] == '-')
  938.                 strcpy(rootdir, NOROOTDIR);
  939.             else {
  940.                 strcpy(rootdir, (++argv)[0]);
  941.                 argc--;
  942.             }
  943.         }
  944.         else if (c == 'l' && strlen(*argv) == 2) {
  945.             logfile = (++argv)[0];
  946.             argc--;
  947.         }
  948.         else if (c == 'd' && d == 'f') {
  949.             domainfile = (++argv)[0];
  950.             argc--;
  951.         }
  952.         else if (c == 't' && strlen(*argv) == 2) {
  953.             toplines = atoi((++argv)[0]);
  954.             argc--;
  955.         }
  956.         else if (c == 'z' && strlen(*argv) == 2)
  957.             usage();
  958.         else
  959.             usage();
  960.         if (argc == 0)
  961.             break;
  962.     }
  963.  
  964.     if (use_stdin == 1) {
  965. #ifdef VMS
  966.         progerr("Can't use standard input under VMS.");
  967. #else
  968.         fp = stdin;
  969. #endif
  970.         showprogress = 0;
  971.     }
  972.  
  973. #ifdef VMS
  974.     else if ((fp = fopen(logfile, "r", "shr=put", "shr=upd")) == NULL)
  975. #else
  976.     else if ((fp = fopen(logfile, "r")) == NULL)
  977. #endif
  978.         progerr("Couldn't open the log file.");
  979.  
  980.     if (isempty(logfile))
  981.         progerr("The log file is empty.");
  982.  
  983.     if (allreports) {
  984.         if (strcmp(monthly_report, "YES"))
  985.             strcpy(monthly_report, "YES");
  986.         if (strcmp(weekly_report, "YES"))
  987.             strcpy(weekly_report, "YES");
  988.         if (strcmp(daysum_report, "YES"))
  989.             strcpy(daysum_report, "YES");
  990.         if (strcmp(daily_report, "YES"))
  991.             strcpy(daily_report, "YES");
  992.         if (strcmp(hoursum_report, "YES"))
  993.             strcpy(hoursum_report, "YES");
  994.         if (strcmp(hourly_report, "YES"))
  995.             strcpy(hourly_report, "YES");
  996.         if (!strcmp(full_report, "NONE") ||
  997.         !strstr(full_report, "FULL"))
  998.             strcpy(full_report, "FULLACCESS");
  999.         if (!strcmp(request_report, "NONE") ||
  1000.         !strstr(request_report, "REQ"))
  1001.             strcpy(request_report, "REQACCESS");
  1002.         if (!strcmp(domain_report, "NONE") ||
  1003.         !strstr(domain_report, "DOM"))
  1004.             strcpy(domain_report, "DOMACCESS");
  1005.         if (strcmp(tree_report, "YES"))
  1006.             strcpy(tree_report, "YES");
  1007.     }
  1008.     fixslash(rootdir);
  1009.     if (!isdirectory(rootdir)) {
  1010.         checkfiles = 0;
  1011.         if (!common)
  1012.             printbytes = 0;
  1013.     }
  1014.     else
  1015.         checkfiles = 1;
  1016.  
  1017.     nowtime = starttime = getthetime();
  1018.     currenttime = localtime((time_t *) &nowtime);
  1019.     sprintf(newshortdate, "%02d/%02d/%02d", currenttime->tm_mon + 1,
  1020.     currenttime->tm_mday, currenttime->tm_year);
  1021.  
  1022.     if (strcmp(addrmask, "NONE"))
  1023.         removespaces(addrmask);
  1024.     if (strcmp(addronlymask, "NONE"))
  1025.         removespaces(addronlymask);
  1026.     if (strcmp(reqmask, "NONE"))
  1027.         removespaces(reqmask);
  1028.     if (strcmp(reqonlymask, "NONE"))
  1029.         removespaces(reqonlymask);
  1030.     if (strcmp(datemask, "ALLDATES"))
  1031.         removespaces(datemask);
  1032.     if (strcmp(hourmask, "ALLHOURS"))
  1033.         removespaces(hourmask);
  1034.     if (strcmp(daymask, "ALLDAYS")) {
  1035.         removespaces(daymask);
  1036.         makelower(daymask);
  1037.     }
  1038.  
  1039.     if (strcmp(datemask, "ALLDATES")) {
  1040.         if (!strcmp(datemask, "today")) {
  1041.             currenttime = localtime((time_t *) &nowtime);
  1042.             sprintf(datemask, "%02d/%02d/%02d",
  1043.             currenttime->tm_mon + 1, currenttime->tm_mday,
  1044.             currenttime->tm_year);
  1045.         }
  1046.         else if (!strcmp(datemask, "yesterday")) {
  1047.             nowtime -= SECSPERDAY;
  1048.             currenttime = localtime((time_t *) &nowtime);
  1049.             sprintf(datemask, "%02d/%02d/%02d",
  1050.             currenttime->tm_mon + 1, currenttime->tm_mday,
  1051.             currenttime->tm_year);
  1052.         }
  1053.         else if (!strcmp(datemask, "thisweek")) {
  1054.             currenttime = localtime((time_t *) &nowtime);
  1055.             strcpy(datemask, (char *)
  1056.             getweekdatemask(currenttime->tm_mon + 1,
  1057.             currenttime->tm_mday, currenttime->tm_year));
  1058.         }
  1059.         else if (!strcmp(datemask, "lastweek")) {
  1060.             nowtime -= SECSPERWEEK;
  1061.             currenttime = localtime((time_t *) &nowtime);
  1062.             strcpy(datemask, (char *)
  1063.             getweekdatemask(currenttime->tm_mon + 1,
  1064.             currenttime->tm_mday, currenttime->tm_year));
  1065.         }
  1066.         else if (!strcmp(datemask, "thismonth")) {
  1067.             currenttime = localtime((time_t *) &nowtime);
  1068.             sprintf(datemask, "%02d/*/%02d",
  1069.             currenttime->tm_mon + 1, currenttime->tm_year);
  1070.         }
  1071.         else if (!strcmp(datemask, "lastmonth")) {
  1072.             currenttime = localtime((time_t *) &nowtime);
  1073.             sprintf(datemask, "%02d/*/%02d",
  1074.             (currenttime->tm_mon + 1 == 1) ? 12 :
  1075.             (currenttime->tm_mon + 1), (currenttime->tm_mon + 1
  1076.             == 1) ? (currenttime->tm_year - 1) :
  1077.             (currenttime->tm_year));
  1078.         }
  1079.         else if (numstrchr(datemask, '/') != 2)
  1080.             progerr("Invalid date string.");
  1081.         parsedatemask(datemask, monthstr, daystr, yearstr);
  1082.     }
  1083.  
  1084.     if (strcmp(hourmask, "ALLHOURS")) {
  1085.         parsehourmask(hourmask, &lowhour, &highhour);
  1086.         if (lowhour > highhour)
  1087.             progerr("Invalid hour string.");
  1088.     }
  1089.     if (strcmp(daymask, "ALLDAYS")) {
  1090.         parsedaymask(daymask, &lowday, &highday);
  1091.         if (lowday > highday)
  1092.             progerr("Invalid day string.");
  1093.     }
  1094.  
  1095.     if (domainlevels < 1)
  1096.         domainlevels = 1;
  1097.  
  1098.     errors = 0;
  1099.     islastline = 0;
  1100.     isfirstline = 1;
  1101.  
  1102.     if (strcmp(error_report, "YES") && strcmp(error_report, "NONE")) {
  1103.         if ((fperr = fopen(error_report, "a+")) == NULL)
  1104.             progerr("Couldn't write to error log.");
  1105.         else
  1106.             fprintf(fperr, "%s run on %s local time:\n\n",
  1107.             PROGNAME, getlocaltime());
  1108.     }
  1109.     else
  1110.         fperr = NULL;
  1111.  
  1112.     if (!strcmp(server_type, "CERN")) {
  1113.         serverfunction = getcerndateaddress;
  1114.         strcpy(server_url, CERNURL);
  1115.     }
  1116.     else if (!strcmp(server_type, "NCSA")) {
  1117.         serverfunction = getncsadateaddress;
  1118.         strcpy(server_url, NCSAURL);
  1119.     }
  1120.     else if (!strcmp(server_type, "PLEXUS")) {
  1121.         serverfunction = getplexdateaddress;
  1122.         strcpy(server_url, PLEXURL);
  1123.     }
  1124.     else if (!strcmp(server_type, "GN")) {
  1125.         serverfunction = getgndateaddress;
  1126.         strcpy(server_url, GNURL);
  1127.     }
  1128.     else if (!strcmp(server_type, "MAC")) {
  1129.         serverfunction = getmacdateaddress;
  1130.         strcpy(server_url, MACURL);
  1131.     }
  1132.     else if (!strcmp(server_type, "GOPHER")) {
  1133.         serverfunction = getgophdateaddress;
  1134.         strcpy(server_url, GOPHURL);
  1135.     }
  1136.     if (common)
  1137.         serverfunction = getcommondateaddress;
  1138.  
  1139.     if (showprogress) {
  1140.         i = 0;
  1141.         fprintf(stderr, "%s %s : %s\n", PROGNAME, VERSION,
  1142.         getlocaltime());
  1143.         setupprogress(logfile);
  1144.     }
  1145.  
  1146.     if (domainfile != NULL)
  1147.         installdomaintable(domainfile);
  1148.  
  1149.     while (fgets(logline, MAXLINE, fp) != NULL) {
  1150.  
  1151.         if (showprogress)
  1152.             updateprogress(i++);
  1153.  
  1154.         if ((*serverfunction)(logline, date, address, request,
  1155.         &filesize) == 0) {
  1156.             errors++;
  1157.             errorreport = (struct errorlist *)
  1158.             adderror(errorreport, logline);
  1159.             continue;
  1160.         }
  1161.  
  1162.         if (strcmp(hourmask, "ALLHOURS") &&
  1163.         !isokhour(date, lowhour, highhour))
  1164.             continue;
  1165.  
  1166.         if (strcmp(daymask, "ALLDAYS") &&
  1167.         !isokday(date, lowday, highday))
  1168.             continue;
  1169.  
  1170.         convtoshortdate(date, shortdate);
  1171.         if (strcmp(datemask, "ALLDATES") &&
  1172.         !isokdate(monthstr, daystr, yearstr, shortdate))
  1173.             continue;
  1174.  
  1175.         if (isip(address)) {
  1176.             if (strstr(address, "0.0.0")) {
  1177.                 errors++;
  1178.                 errorreport = (struct errorlist *)
  1179.                 adderror(errorreport, logline);
  1180.                 continue;
  1181.             }
  1182.             if (!strcmp(lookup, "YES"))
  1183.                 strcpy(address, (char *)
  1184.                 lookupnumaddr(address));
  1185.             makelower(address);
  1186.         }
  1187.         else {
  1188.             if (address[0] == ' ' || address[0] == (char) NULL) {
  1189.                 errors++;
  1190.                 errorreport = (struct errorlist *)
  1191.                 adderror(errorreport, logline);
  1192.                 continue;
  1193.             }
  1194.             makelower(address);
  1195.         }
  1196.  
  1197.         if (!isokstring(address, addrmask, 1))
  1198.             continue;
  1199.         if (!isokstring(address, addronlymask, 0))
  1200.             continue;
  1201.         if (!isokstring(request, reqmask, 1))
  1202.             continue;
  1203.         if (!isokstring(request, reqonlymask, 0))
  1204.             continue;
  1205.  
  1206.         if (ishtmlrequest(request))
  1207.             htmldocnum++;
  1208.         else if (isscriptrequest(request))
  1209.             scriptnum++;
  1210.         else
  1211.             assetnum++;
  1212.  
  1213.         if (printbytes) {
  1214.             if (!common)
  1215.                 filesize = getsize(request);
  1216.             bytecount += filesize;
  1217.         }
  1218.  
  1219.         if (!strcmp(monthly_report, "YES"))
  1220.             analyzemonthly(shortdate, filesize, islastline);
  1221.         if (!strcmp(weekly_report, "YES"))
  1222.             analyzeweekly(shortdate, filesize, islastline);
  1223.         if (!strcmp(daysum_report, "YES"))
  1224.             analyzedaysum(shortdate, filesize);
  1225.         if (!strcmp(daily_report, "YES"))
  1226.             analyzedaily(shortdate, filesize, islastline);
  1227.         if (!strcmp(hoursum_report, "YES"))
  1228.             analyzehoursum(date, filesize);
  1229.         if (!strcmp(hourly_report, "YES"))
  1230.             analyzehourly(date, filesize, islastline);
  1231.  
  1232.         if (isinlastweek(shortdate, newshortdate)) {
  1233.             islastweek = 1;
  1234.             lastweeksrequests++;
  1235.         }
  1236.         else
  1237.             islastweek = 0;
  1238.  
  1239.         longdate = convtoyearsecs(date);
  1240.  
  1241.         list = (struct entry *) addentry(list, address, longdate,
  1242.         islastweek, filesize);
  1243.  
  1244.         if (strcmp(request_report, "NONE"))
  1245.             requestlist = (struct requestentry *)
  1246.             addrequestentry(requestlist, request, longdate,
  1247.             filesize);
  1248.  
  1249.         if (strcmp(domain_report, "NONE"))
  1250.             getdomain(address, longdate, domainlevels, filesize);
  1251.  
  1252.         if (strcmp(tree_report, "NONE")) {
  1253.             treereqlist = (struct requestentry *)
  1254.             addrequestentry(treereqlist, request, longdate,
  1255.             filesize);
  1256.             addtreeentry(request, longdate, filesize);
  1257.         }
  1258.  
  1259.         if (isfirstline) {
  1260.             strcpy(firstdate, date);
  1261.             isfirstline = 0;
  1262.         }
  1263.         strcpy(lastdate, date);
  1264.  
  1265.     }
  1266.     fclose(fp);
  1267.  
  1268.     if (strcmp(error_report, "NONE") && !errors)
  1269.         errorreport = (struct errorlist *)
  1270.         adderror(errorreport, "No malformed requests reported.");
  1271.  
  1272.     if (fperr != NULL) {
  1273.         printerrors(errorreport, fperr);
  1274.         fprintf(fperr, "\n");
  1275.         if (!errors)
  1276.             fprintf(fperr, "\n");
  1277.         fclose(fperr);
  1278.     }
  1279.  
  1280.     if (showprogress) {
  1281.         if (!(loglines % linespermark))
  1282.             fprintf(stderr, "*\n");
  1283.         else
  1284.             fprintf(stderr, "\n");
  1285.         fprintf(stderr, "Printing reports...\n");
  1286.         fflush(stderr);
  1287.     }
  1288.  
  1289.     stoptime = getthetime();
  1290.     islastline = 1;
  1291.  
  1292.     if (!strcmp(monthly_report, "YES"))
  1293.         analyzemonthly(shortdate, filesize, islastline);
  1294.     if (!strcmp(weekly_report, "YES"))
  1295.         analyzeweekly(shortdate, filesize, islastline);
  1296.     if (!strcmp(daily_report, "YES"))
  1297.         analyzedaily(shortdate, filesize, islastline);
  1298.     if (!strcmp(hourly_report, "YES"))
  1299.         analyzehourly(date, filesize, islastline);
  1300.  
  1301.     if (printhtml) {
  1302. #ifdef CGI
  1303.         printf("Content-type: text/html\n\n");
  1304. #endif
  1305.         printf("<head>\n<title>%s</title>\n</head>\n", HTMLTITLE);
  1306.         printf("<body><h1>");
  1307. #ifdef USEHTMLICON
  1308.         printf("<img src=\"%s\" alt=\"[*]\">  ", USEHTMLICON);
  1309. #endif
  1310.         printf("%s</h1>\n<p>\n<hr>\n", HTMLTITLE);
  1311.         printf("<a name=\"general\"><h2>HTTP Server General ");
  1312.         printf("Statistics</h2></a><pre>\n");
  1313.     }
  1314.     else
  1315.         printf("HTTP Server General Statistics\n");
  1316.     printheader(server_type, common);
  1317.     if (htmldocnum || scriptnum || assetnum)
  1318.         printcovers(firstdate, lastdate);
  1319.  
  1320.     if (printhtml)
  1321.         putchar('\n');
  1322.     printstats(lastweeksrequests, htmldocnum, scriptnum, assetnum,
  1323.     bytecount, errors);
  1324.     if (htmldocnum || scriptnum || assetnum)
  1325.         printdates(firstdate, lastdate, htmldocnum + scriptnum +
  1326.         assetnum + errors, bytecount);
  1327.     printrunning(starttime, stoptime);
  1328.  
  1329.     if (printhtml) {
  1330.         printf("</pre>\n");
  1331.         if (strcmp(concise_report, "YES")) {
  1332.             printf("<p>\n<blockquote>");
  1333.             printf("<b>Go to:</b> ");
  1334.             if (!strcmp(monthly_report, "YES")) {
  1335.                 printf("<a href=\"#monthly\">");
  1336.                 printf("[Monthly report]</a>\n");
  1337.             }
  1338.             if (!strcmp(weekly_report, "YES")) {
  1339.                 printf("<a href=\"#weekly\">");
  1340.                 printf("[Weekly report]</a>\n");
  1341.             }
  1342.             if (!strcmp(daysum_report, "YES")) {
  1343.                 printf("<a href=\"#daysum\">");
  1344.                 printf("[Daily summary]</a>\n");
  1345.             }
  1346.             if (!strcmp(daily_report, "YES")) {
  1347.                 printf("<a href=\"#daily\">");
  1348.                 printf("[Daily report]</a>\n");
  1349.             }
  1350.             if (!strcmp(hoursum_report, "YES")) {
  1351.                 printf("<a href=\"#hoursum\">");
  1352.                 printf("[Hourly summary]</a>\n");
  1353.             }
  1354.             if (!strcmp(hourly_report, "YES")) {
  1355.                 printf("<a href=\"#hourly\">");
  1356.                 printf("[Hourly report]</a>\n");
  1357.             }
  1358.             if (strcmp(full_report, "NONE")) {
  1359.                 printf("<a href=\"#full\">");
  1360.                 printf("[Full (host) report]</a>\n");
  1361.             }
  1362.             if (strcmp(request_report, "NONE")) {
  1363.                 printf("<a href=\"#request\">");
  1364.                 printf("[Request report]</a>\n");
  1365.             }
  1366.             if (strcmp(domain_report, "NONE")) {
  1367.                 printf("<a href=\"#domain\">");
  1368.                 printf("[Domain report]</a>\n");
  1369.             }
  1370.             if (strcmp(tree_report, "NONE")) {
  1371.                 printf("<a href=\"#tree\">");
  1372.                 printf("[Directory tree report]</a>\n");
  1373.             }
  1374.             if (!strcmp(error_report, "YES")) {
  1375.                 printf("<a href=\"#error\">");
  1376.                 printf("[Error report]</a>\n");
  1377.             }
  1378.             printf("</blockquote>\n<p>\n");
  1379.         }
  1380.         printf("<p>\n<hr>\n");
  1381.     }
  1382.  
  1383.     if (!(htmldocnum + scriptnum + assetnum))
  1384.         noactivity();
  1385.  
  1386.     if (!strcmp(concise_report, "YES")) {
  1387.         if (printhtml)
  1388.             printbottomhtml();
  1389. #ifdef VMS
  1390.         exit(1);
  1391. #else
  1392.         exit(0);
  1393. #endif
  1394.     }
  1395.     if (!strcmp(monthly_report, "YES")) {
  1396.         printmonthlyheader(firstdate, lastdate);
  1397.         printgraphreport(monthlyreport, "monthly");
  1398.         if (printhtml)
  1399.             printf("</%s><hr>\n", REPORTTAG);
  1400.         else {
  1401.             putchar('\n');
  1402.             printbreak();
  1403.         }
  1404.     }
  1405.     if (!strcmp(weekly_report, "YES")) {
  1406.         printweeklyheader(firstdate, lastdate);
  1407.         printgraphreport(weeklyreport, "weekly");
  1408.         if (printhtml)
  1409.             printf("</%s><hr>\n", REPORTTAG);
  1410.         else {
  1411.             putchar('\n');
  1412.             printbreak();
  1413.         }
  1414.     }
  1415.     if (!strcmp(daysum_report, "YES")) {
  1416.         printdaysumheader(firstdate, lastdate);
  1417.         printsummary("daily");
  1418.         if (printhtml)
  1419.             printf("</%s><hr>\n", REPORTTAG);
  1420.         else {
  1421.             putchar('\n');
  1422.             printbreak();
  1423.         }
  1424.     }
  1425.     if (!strcmp(daily_report, "YES")) {
  1426.         printdailyheader(firstdate, lastdate);
  1427.         printgraphreport(dailyreport, "daily");
  1428.         if (printhtml)
  1429.             printf("</%s><hr>\n", REPORTTAG);
  1430.         else {
  1431.             putchar('\n');
  1432.             printbreak();
  1433.         }
  1434.     }
  1435.     if (!strcmp(hoursum_report, "YES")) {
  1436.         printhoursumheader(firstdate, lastdate);
  1437.         printsummary("hourly");
  1438.         if (printhtml)
  1439.             printf("</%s><hr>\n", REPORTTAG);
  1440.         else {
  1441.             putchar('\n');
  1442.             printbreak();
  1443.         }
  1444.     }
  1445.     if (!strcmp(hourly_report, "YES")) {
  1446.         printhourlyheader(firstdate, lastdate);
  1447.         printgraphreport(hourlyreport, "hourly");
  1448.         if (printhtml)
  1449.             printf("</%s><hr>\n", REPORTTAG);
  1450.         else {
  1451.             putchar('\n');
  1452.             printbreak();
  1453.         }
  1454.     }
  1455.     if (strcmp(full_report, "NONE")) {
  1456.         sortreport(list);
  1457.         docfieldlen = numlen(largestdocnum) + 1;
  1458.         bytefieldlen = numlen(largestbytenum) + 1;
  1459.         printfullheader(full_report, firstdate, lastdate);
  1460.         printreport(sortedlist, docfieldlen, bytefieldlen);
  1461.         if (printhtml)
  1462.             printf("</%s><hr>\n", REPORTTAG);
  1463.         else {
  1464.             putchar('\n');
  1465.             printbreak();
  1466.         }
  1467.     }
  1468.     if (strcmp(request_report, "NONE")) {
  1469.         largestbytenum = 0;
  1470.         sortrequests(requestlist);
  1471.         reqfieldlen = numlen(largestreqnum) + 1;
  1472.         bytefieldlen = numlen(largestbytenum) + 1;
  1473.         sizefieldlen = numlen(largestfilesizenum) + 1;
  1474.         printreqheader(request_report, firstdate, lastdate);
  1475.         printrequests(sortedrequestlist, reqfieldlen, bytefieldlen,
  1476.         sizefieldlen);
  1477.         if (printhtml)
  1478. #ifdef PRINTURLS
  1479.             printf("</%s><hr>\n", PRINTURLS);
  1480. #else
  1481.             printf("</%s><hr>\n", REPORTTAG);
  1482. #endif
  1483.         else {
  1484.             putchar('\n');
  1485.             printbreak();
  1486.         }
  1487.     }
  1488.     if (strcmp(domain_report, "NONE")) {
  1489.         largestbytenum = 0;
  1490.         sortdomains(domainlist);
  1491.         domfieldlen = numlen(largestdomnum) + 1;
  1492.         bytefieldlen = numlen(largestbytenum) + 1;
  1493.         uniqfieldlen = numlen(largestudomnum) + 1;
  1494.         printdomheader(domain_report, domainlevels, firstdate,
  1495.         lastdate);
  1496.         printdomains(sorteddomainlist, domfieldlen, bytefieldlen,
  1497.         uniqfieldlen);
  1498.         if (printhtml)
  1499.             printf("</%s><hr>\n", REPORTTAG);
  1500.         else {
  1501.             putchar('\n');
  1502.             printbreak();
  1503.         }
  1504.     }
  1505.     if (strcmp(tree_report, "NONE")) {
  1506.         strcpy(request_report, "REQUEST");
  1507.         sortrequests(treereqlist);
  1508.         printtreeheader(firstdate, lastdate);
  1509.         reqfieldlen = numlen(largetreereqnum) + 1;
  1510.         bytefieldlen = numlen(largetreebytenum) + 1;
  1511.         printtree(treereqlist, reqfieldlen, bytefieldlen);
  1512.         if (printhtml)
  1513.             printf("</%s><hr>\n", REPORTTAG);
  1514.         else {
  1515.             putchar('\n');
  1516.             printbreak();
  1517.         }
  1518.     }
  1519.     if (strcmp(error_report, "NONE") && fperr == NULL) {
  1520.         printerrorheader(firstdate, lastdate);
  1521.         printerrors(errorreport, stdout);
  1522.         if (printhtml)
  1523.             printf("</%s><hr>\n", REPORTTAG);
  1524.         else {
  1525.             putchar('\n');
  1526.             if (!errors)
  1527.                 putchar('\n');
  1528.             printbreak();
  1529.         }
  1530.     }
  1531.  
  1532.     if (printhtml)
  1533.         printbottomhtml();
  1534.  
  1535. #ifdef VMS
  1536.     exit(1);
  1537. #else
  1538.     exit(0);
  1539. #endif
  1540. }
  1541.  
  1542. void printfullheader(report_type, firstdate, lastdate)
  1543.      char *report_type;
  1544.      char *firstdate;
  1545.      char *lastdate;
  1546. {
  1547.     putchar('\n');
  1548.     if (printhtml) {
  1549.         printf("<a name=\"full\"><h2>HTTP Server Full Statistics");
  1550.         printf("</a> (See <a href=\"#general\">general");
  1551.         printf("</a> statistics)</h2><i>\n");
  1552.     }
  1553.     else
  1554.         printf("HTTP Server Full Statistics\n");
  1555.     printcovers(firstdate, lastdate);
  1556.     if (printhtml)
  1557.         printf("<br>");
  1558.     printf("Sorted by ");
  1559.     if (!strcmp(report_type, "FULLADDR"))
  1560.         printf("address.\n");
  1561.     else if (!strcmp(report_type, "FULLACCESS"))
  1562.         printf("number of requests.\n");
  1563.     else if (!strcmp(report_type, "FULLDATE"))
  1564.         printf("last access date.\n");
  1565.     else if (!strcmp(report_type, "FULLBYTES"))
  1566.         printf("byte traffic.\n");
  1567.     if (printhtml)
  1568.         printf("</i>\n<p>\n");
  1569.     if (printhtml)
  1570.         printf("<%s>", REPORTTAG);
  1571.     putchar('\n');
  1572.     printf("# of Requests : Last Access ");
  1573.     if (printbytes)
  1574.         printf("(%s) : Bytes : Hostname\n", DATEFORMAT);
  1575.     else
  1576.         printf("(%s) : Hostname\n", DATEFORMAT);
  1577.     printbreak();
  1578.     putchar('\n');
  1579. }
  1580.  
  1581. void printmonthlyheader(firstdate, lastdate)
  1582.      char *firstdate;
  1583.      char *lastdate;
  1584. {
  1585.     putchar('\n');
  1586.     if (printhtml) {
  1587.         printf("<a name=\"monthly\"><h2>HTTP Server Monthly ");
  1588.         printf("Statistics");
  1589.         printf("</a> (See <a href=\"#general\">general");
  1590.         printf("</a> statistics)</h2>\n");
  1591.     }
  1592.     else
  1593.         printf("HTTP Server Monthly Statistics\n");
  1594.     printcovers(firstdate, lastdate);
  1595.     if (printhtml)
  1596.         printf("<%s>", REPORTTAG);
  1597.     putchar('\n');
  1598.     printf("Each mark (%c) represents %d requests.\n", MARK, MONTHMARK);
  1599.     if (printbytes)
  1600.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1601.         MONTHBYTEMARK);
  1602.     printbreak();
  1603.     putchar('\n');
  1604. }
  1605.  
  1606. void printweeklyheader(firstdate, lastdate)
  1607.      char *firstdate;
  1608.      char *lastdate;
  1609. {
  1610.     putchar('\n');
  1611.     if (printhtml) {
  1612.         printf("<a name=\"weekly\"><h2>HTTP Server Weekly Statistics");
  1613.         printf("</a> (See <a href=\"#general\">general");
  1614.         printf("</a> statistics)</h2>\n");
  1615.     }
  1616.     else
  1617.         printf("HTTP Server Weekly Statistics\n");
  1618.     printcovers(firstdate, lastdate);
  1619.     if (printhtml)
  1620.         printf("<%s>", REPORTTAG);
  1621.     putchar('\n');
  1622.     printf("Each mark (%c) represents %d requests.\n", MARK, WEEKMARK);
  1623.     if (printbytes)
  1624.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1625.         WEEKBYTEMARK);
  1626.     printbreak();
  1627.     putchar('\n');
  1628. }
  1629.  
  1630. void printdaysumheader(firstdate, lastdate)
  1631.      char *firstdate;
  1632.      char *lastdate;
  1633. {
  1634.     putchar('\n');
  1635.     if (printhtml) {
  1636.         printf("<a name=\"daysum\"><h2>HTTP Server Daily Summary");
  1637.         printf("</a> (See <a href=\"#general\">general");
  1638.         printf("</a> statistics)</h2>\n");
  1639.     }
  1640.     else
  1641.         printf("HTTP Server Daily Summary\n");
  1642.     printcovers(firstdate, lastdate);
  1643.     if (printhtml)
  1644.         printf("<%s>", REPORTTAG);
  1645.     putchar('\n');
  1646.     printf("Each mark (%c) represents %d requests.\n", MARK, DAYSUMMARK);
  1647.     if (printbytes)
  1648.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1649.         DAYSUMBYTEMARK);
  1650.     printbreak();
  1651.     putchar('\n');
  1652. }
  1653.  
  1654. void printdailyheader(firstdate, lastdate)
  1655.      char *firstdate;
  1656.      char *lastdate;
  1657. {
  1658.     putchar('\n');
  1659.     if (printhtml) {
  1660.         printf("<a name=\"daily\"><h2>HTTP Server Daily Statistics");
  1661.         printf("</a> (See <a href=\"#general\">general");
  1662.         printf("</a> statistics)</h2>\n");
  1663.     }
  1664.     else
  1665.         printf("HTTP Server Daily Statistics\n");
  1666.     printcovers(firstdate, lastdate);
  1667.     if (printhtml)
  1668.         printf("<%s>", REPORTTAG);
  1669.     putchar('\n');
  1670.     printf("Each mark (%c) represents %d requests.\n", MARK, DAYMARK);
  1671.     if (printbytes)
  1672.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1673.         DAYBYTEMARK);
  1674.     printbreak();
  1675.     putchar('\n');
  1676. }
  1677.  
  1678. void printhoursumheader(firstdate, lastdate)
  1679.      char *firstdate;
  1680.      char *lastdate;
  1681. {
  1682.     putchar('\n');
  1683.     if (printhtml) {
  1684.         printf("<a name=\"hoursum\"><h2>HTTP Server Hourly Summary");
  1685.         printf("</a> (See <a href=\"#general\">general");
  1686.         printf("</a> statistics)</h2>\n");
  1687.     }
  1688.     else
  1689.         printf("HTTP Server Hourly Summary\n");
  1690.     printcovers(firstdate, lastdate);
  1691.     if (printhtml)
  1692.         printf("<%s>", REPORTTAG);
  1693.     putchar('\n');
  1694.     printf("Each mark (%c) represents %d requests.\n", MARK, HOURSUMMARK);
  1695.     if (printbytes)
  1696.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1697.         HOURSUMBYTEMARK);
  1698.     printbreak();
  1699.     putchar('\n');
  1700. }
  1701.  
  1702. void printhourlyheader(firstdate, lastdate)
  1703.      char *firstdate;
  1704.      char *lastdate;
  1705. {
  1706.     putchar('\n');
  1707.     if (printhtml) {
  1708.         printf("<a name=\"hourly\"><h2>HTTP Server Hourly Statistics");
  1709.         printf("</a> (See <a href=\"#general\">general");
  1710.         printf("</a> statistics)</h2>\n");
  1711.     }
  1712.     else
  1713.         printf("HTTP Server Hourly Statistics\n");
  1714.     printcovers(firstdate, lastdate);
  1715.     if (printhtml)
  1716.         printf("<%s>", REPORTTAG);
  1717.     putchar('\n');
  1718.     printf("Each mark (%c) represents %d requests.\n", MARK, HOURMARK);
  1719.     if (printbytes)
  1720.         printf("Each mark (%c) represents %d bytes.\n", BYTEMARK,
  1721.         HOURBYTEMARK);
  1722.     printbreak();
  1723. }
  1724.  
  1725. void printreqheader(report_type, firstdate, lastdate)
  1726.      char *report_type;
  1727.      char *firstdate;
  1728.      char *lastdate;
  1729. {
  1730.     putchar('\n');
  1731.     if (printhtml) {
  1732.         printf("<a name=\"request\"><h2>HTTP Server Request ");
  1733.         printf("Statistics");
  1734.         printf("</a> (See <a href=\"#general\">general");
  1735.         printf("</a> statistics)</h2><i>\n");
  1736.     }
  1737.     else
  1738.         printf("HTTP Server Request Statistics\n");
  1739.     printcovers(firstdate, lastdate);
  1740.     if (printhtml)
  1741.         printf("<br>");
  1742.     printf("Sorted by ");
  1743.     if (!strcmp(report_type, "REQUEST"))
  1744.         printf("request name,");
  1745.     else if (!strcmp(report_type, "REQACCESS"))
  1746.         printf("number of requests,");
  1747.     else if (!strcmp(report_type, "REQDATE"))
  1748.         printf("last access date,");
  1749.     else if (!strcmp(report_type, "REQBYTES"))
  1750.         printf("byte traffic,");
  1751.     else if (!strcmp(report_type, "REQFILE"))
  1752.         printf("file size,");
  1753.     printf(" %d unique requests.\n", uniquereqnum);
  1754.     if (printhtml)
  1755.         printf("</i>\n<p>\n");
  1756.     if (printhtml)
  1757. #ifdef PRINTURLS
  1758.         printf("<%s>", PRINTURLS);
  1759. #else
  1760.         printf("<%s>", REPORTTAG);
  1761. #endif
  1762.     putchar('\n');
  1763.     if (printbytes) {
  1764.         printf("# of requests : Last Access (%s) : Bytes/File : ",
  1765.         DATEFORMAT);
  1766.         printf("Request\n");
  1767.     }
  1768.     else
  1769.         printf("# of requests : Last Access (%s) : Request\n",
  1770.         DATEFORMAT);
  1771.     printbreak();
  1772.     putchar('\n');
  1773. }
  1774.  
  1775. void printdomheader(report_type, levels, firstdate, lastdate)
  1776.      char *report_type;
  1777.      int levels;
  1778.      char *firstdate;
  1779.      char *lastdate;
  1780. {
  1781.     putchar('\n');
  1782.     if (printhtml) {
  1783.         printf("<a name=\"domain\"><h2>HTTP Server Domain Statistics");
  1784.         printf("</a> (See <a href=\"#general\">general");
  1785.         printf("</a> statistics)</h2><i>\n");
  1786.     }
  1787.     else
  1788.         printf("HTTP Server Domain Statistics\n");
  1789.     printcovers(firstdate, lastdate);
  1790.     if (printhtml)
  1791.         printf("<br>");
  1792.     printf("%d level%s, sorted by ", levels, (levels == 1) ? "" : "s");
  1793.     if (!strcmp(report_type, "DOMAIN"))
  1794.         printf("domain name,");
  1795.     else if (!strcmp(report_type, "DOMACCESS"))
  1796.         printf("number of requests,");
  1797.     else if (!strcmp(report_type, "DOMUNIQ"))
  1798.         printf("number of unique domains,");
  1799.     else if (!strcmp(report_type, "DOMDATE"))
  1800.         printf("last access date,");
  1801.     else if (!strcmp(report_type, "DOMBYTES"))
  1802.         printf("byte traffic,");
  1803.     printf(" %d unique domains.\n", uniquedomnum);
  1804.     if (printhtml)
  1805.         printf("</i>\n<p>\n");
  1806.     if (printhtml)
  1807.         printf("<%s>", REPORTTAG);
  1808.     putchar('\n');
  1809.     if (printbytes) {
  1810.         printf("# reqs : # uniq : Last Access (%s) : Bytes : ",
  1811.         DATEFORMAT);
  1812.         printf("Domain\n");
  1813.     }
  1814.     else
  1815.         printf("# reqs : # uniq : Last Access (%s) : Domain\n",
  1816.         DATEFORMAT);
  1817.     printbreak();
  1818.     putchar('\n');
  1819. }
  1820.  
  1821. void printbreak()
  1822. {
  1823.     int i = BREAKLEN;
  1824.  
  1825.     if (printbytes)
  1826.         i += 13;
  1827.     while (i--)
  1828.         putchar('-');
  1829.     putchar('\n');
  1830. }
  1831.  
  1832. void printtreeheader(firstdate, lastdate)
  1833.      char *firstdate;
  1834.      char *lastdate;
  1835. {
  1836.     putchar('\n');
  1837.     if (printhtml) {
  1838.         printf("<a name=\"tree\"><h2>HTTP Server Tree Report");
  1839.         printf("</a> (See <a href=\"#general\">general");
  1840.         printf("</a> statistics)</h2>\n");
  1841.     }
  1842.     else
  1843.         printf("HTTP Server Tree Report\n");
  1844.     printcovers(firstdate, lastdate);
  1845.     if (printhtml)
  1846.         printf("<%s>", REPORTTAG);
  1847.     putchar('\n');
  1848.     printf("# of Requests : Last Access ");
  1849.     if (printbytes)
  1850.         printf("(%s) : Bytes : Dir/File\n", DATEFORMAT);
  1851.     else
  1852.         printf("(%s) : Dir/File\n", DATEFORMAT);
  1853.     printbreak();
  1854.     putchar('\n');
  1855. }
  1856.  
  1857. void printerrorheader(firstdate, lastdate)
  1858.      char *firstdate;
  1859.      char *lastdate;
  1860. {
  1861.     putchar('\n');
  1862.     if (printhtml) {
  1863.         printf("<a name=\"error\"><h2>HTTP Server Error Report");
  1864.         printf(" (All Dates)</a> (See <a href=\"#general\">general");
  1865.         printf("</a> statistics)</h2>\n");
  1866.     }
  1867.     else
  1868.         printf("HTTP Server Error Report (All Dates)\n");
  1869.     if (printhtml)
  1870.         printf("<%s>", REPORTTAG);
  1871.     putchar('\n');
  1872.     printbreak();
  1873.     putchar('\n');
  1874. }
  1875.  
  1876. void printheader(server_type, iscommon)
  1877.      char *server_type;
  1878.      int iscommon;
  1879. {
  1880.     if (printhtml) {
  1881.         printf("<b>Server:</b> <a href=\"%s\">%s</a>",
  1882.         SERVERSITE, SERVERSITE);
  1883.         printf(" (<a href=\"%s\">%s</a>%s)\n", server_url,
  1884.         server_type, (iscommon) ? " Common" : "");
  1885.         printf("<b>Local date:</b> <i>%s</i>\n", getlocaltime());
  1886.     }
  1887.     else {
  1888.         printf("Server: %s (%s%s)\n", SERVERSITE, server_type,
  1889.         (iscommon) ? " Common" : "");
  1890.         printf("Local date: %s\n", getlocaltime());
  1891.     }
  1892. }
  1893.  
  1894. void printstats(lastweeksrequests, htmldocnum, scriptnum, assetnum, bytecount, errors)
  1895.      int lastweeksrequests;
  1896.      int htmldocnum;
  1897.      int scriptnum;
  1898.      int assetnum;
  1899.      long int bytecount;
  1900.      int errors;
  1901. {
  1902.     printf("Requests last 7 days: %d\n", lastweeksrequests);
  1903.     printf("New unique hosts last 7 days: %d\n", lastweekshosts);
  1904.     printf("Total unique hosts: %d\n", uniquehostnum);
  1905.     printf("Number of HTML requests: %d\n", htmldocnum);
  1906.     printf("Number of script requests: %d\n", scriptnum);
  1907.     printf("Number of non-HTML requests: %d\n", assetnum);
  1908.     printf("Number of malformed requests (all dates): %d\n", errors);
  1909.     printf("Total number of all requests/errors: %d\n", htmldocnum +
  1910.     scriptnum + assetnum + errors);
  1911.     if (printbytes)
  1912.         printf("Total number of bytes requested: %d\n", bytecount);
  1913. }
  1914.  
  1915. void printdates(firstlongdate, lastlongdate, requests, bytecount)
  1916.      char *firstlongdate;
  1917.      char *lastlongdate;
  1918.      int requests;
  1919.      long int bytecount;
  1920. {
  1921.     int firstsecs, lastsecs;
  1922.     float hours;
  1923.  
  1924.     firstsecs = (int) convtoyearsecs(firstlongdate);
  1925.     lastsecs = (int) convtoyearsecs(lastlongdate);
  1926.     hours = (float) ((float) (lastsecs - firstsecs) / (float) SECSPERHOUR);
  1927.     if (hours) {
  1928.         if (hours < 1)
  1929.             hours = 1;
  1930.         printf("Average requests/hour: %.1f, ",
  1931.         (float) requests / (float) hours);
  1932.         printf("requests/day: %.1f\n",
  1933.         ((float) requests / (float) hours) * ((hours < HOURSPERDAY) ?
  1934.         hours : HOURSPERDAY));
  1935.     }
  1936.     if (printbytes && hours) {
  1937.         printf("Average bytes/hour: %.0f, ",
  1938.         (float) bytecount / (float) hours);
  1939.         printf("bytes/day: %.0f\n",
  1940.         ((float) bytecount / (float) hours) * ((hours < HOURSPERDAY) ?
  1941.         hours : HOURSPERDAY));
  1942.     }
  1943. }
  1944.  
  1945. void printrunning(starttime, stoptime)
  1946.      long int starttime;
  1947.      long int stoptime;
  1948. {
  1949.     int minutes, seconds;
  1950.  
  1951.     minutes = (stoptime - starttime) / SECSPERMIN;
  1952.     seconds = (stoptime - starttime) % SECSPERMIN;
  1953.     printf("Running time: ");
  1954.     if (minutes)
  1955.         printf("%d minute%s", minutes, (minutes == 1) ? "" : "s");
  1956.     if (minutes && seconds)
  1957.         printf(", ");
  1958.     if (seconds)
  1959.         printf("%d second%s", seconds, (seconds == 1) ? "" : "s");
  1960.     if (!minutes && !seconds)
  1961.         printf("Less than a second");
  1962.     printf(".\n");
  1963. }
  1964.  
  1965. void printcovers(firstlongdate, lastlongdate)
  1966.      char *firstlongdate;
  1967.      char *lastlongdate;
  1968. {
  1969.     char firstdate[SHORTDATELEN], lastdate[SHORTDATELEN];
  1970.  
  1971.     convtoshortdate(firstlongdate, firstdate);
  1972.     convtoshortdate(lastlongdate, lastdate);
  1973.     if (!strcmp(firstdate, lastdate)) {
  1974.         if (printhtml)
  1975.             printf("<b>");
  1976.         printf("This report covers the day of %s.",
  1977.         convtoeurodate(firstdate));
  1978.         if (printhtml)
  1979.             printf("</b>");
  1980.         putchar('\n');
  1981.     }
  1982.     else {
  1983.         if (printhtml)
  1984.             printf("<b>Covers:</b> <i>");
  1985.         else
  1986.             printf("Covers: ");
  1987.         printf("%s to %s", convtoeurodate(firstdate),
  1988.         convtoeurodate(lastdate));
  1989.         printf(" (%d days).", daydifference(firstdate, lastdate) + 1);
  1990.         if (printhtml)
  1991.             printf("</i>");
  1992.         putchar('\n');
  1993.     }
  1994.     if (printhtml)
  1995.         printf("<b>");
  1996. #ifndef GMTOFFSET
  1997.     printf("All dates are in %s time.\n", LOGTZ);
  1998. #else
  1999.     printf("All dates are in local time.\n");
  2000. #endif
  2001.     if (printhtml)
  2002.         printf("</b>");
  2003. }
  2004.  
  2005. void analyzemonthly(shortdate, filesize, islastline)
  2006.      char *shortdate;
  2007.      long int filesize;
  2008.      int islastline;
  2009. {
  2010.     int monthnum;
  2011.     static int starting, monthlyrequests, prevmonthnum;
  2012.     static long bytecount;
  2013.  
  2014.     monthnum = ((shortdate[0] - '0') * 1000) + ((shortdate[1] - '0') * 100)
  2015.     + ((shortdate[6] - '0') * 10) + (shortdate[7] - '0');
  2016.  
  2017.     if (!starting) {
  2018.         starting = 1;
  2019.         monthlyreport = (struct node *) addnode(monthlyreport,
  2020.             shortdate, -1, 0, 0, -1, "monthly");
  2021.         bytecount += filesize;
  2022.         monthlyrequests++;
  2023.         prevmonthnum = monthnum;
  2024.         return;
  2025.     }
  2026.     if (monthnum != prevmonthnum) {
  2027.         monthlyreport = (struct node *) addnode(monthlyreport, NULL,
  2028.             monthlyrequests, 0, 0, bytecount, "monthly");
  2029.         if (monthlyrequests > largestmonthnum)
  2030.             largestmonthnum = monthlyrequests;
  2031.         if (bytecount > largestmonthnum)
  2032.             largestmonthnum = bytecount;
  2033.         if (islastline)
  2034.             return;
  2035.         monthlyreport = (struct node *) addnode(monthlyreport,
  2036.             shortdate, -1, 0, 0, -1, "monthly");
  2037.         monthlyrequests = bytecount = 0;
  2038.     }
  2039.  
  2040.     if (islastline) {
  2041.         monthlyreport = (struct node *) addnode(monthlyreport, NULL,
  2042.             monthlyrequests, 0, 0, bytecount, "monthly");
  2043.         if (monthlyrequests > largestmonthnum)
  2044.             largestmonthnum = monthlyrequests;
  2045.         if (bytecount > largestmonthnum)
  2046.             largestmonthnum = bytecount;
  2047.     }
  2048.     else {
  2049.         prevmonthnum = monthnum;
  2050.         bytecount += filesize;
  2051.         monthlyrequests++;
  2052.     }
  2053. }
  2054.  
  2055. void analyzeweekly(shortdate, filesize, islastline)
  2056.      char *shortdate;
  2057.      long int filesize;
  2058.      int islastline;
  2059. {
  2060.     int mondaynum;
  2061.     static int starting, weeklyrequests, prevmondaynum;
  2062.     static long bytecount;
  2063.  
  2064.     mondaynum = getmondaynum(shortdate);
  2065.  
  2066.     if (!starting) {
  2067.         starting = 1;
  2068.         weeklyreport = (struct node *) addnode(weeklyreport, shortdate,
  2069.             -1, 0, 0, -1, "weekly");
  2070.         bytecount += filesize;
  2071.         weeklyrequests++;
  2072.         prevmondaynum = mondaynum;
  2073.         return;
  2074.     }
  2075.     if (mondaynum != prevmondaynum) {
  2076.         weeklyreport = (struct node *) addnode(weeklyreport, NULL,
  2077.             weeklyrequests, 0, 0, bytecount, "weekly");
  2078.         if (weeklyrequests > largestweeknum)
  2079.             largestweeknum = weeklyrequests;
  2080.         if (bytecount > largestweeknum)
  2081.             largestweeknum = bytecount;
  2082.         if (islastline)
  2083.             return;
  2084.         weeklyreport = (struct node *) addnode(weeklyreport, shortdate,
  2085.             -1, 0, 0, -1, "weekly");
  2086.         weeklyrequests = bytecount = 0;
  2087.     }
  2088.  
  2089.     if (islastline) {
  2090.         weeklyreport = (struct node *) addnode(weeklyreport, NULL,
  2091.             weeklyrequests, 0, 0, bytecount, "weekly");
  2092.         if (weeklyrequests > largestweeknum)
  2093.             largestweeknum = weeklyrequests;
  2094.         if (bytecount > largestweeknum)
  2095.             largestweeknum = bytecount;
  2096.     }
  2097.     else {
  2098.         prevmondaynum = mondaynum;
  2099.         bytecount += filesize;
  2100.         weeklyrequests++;
  2101.     }
  2102. }
  2103.  
  2104. void analyzedaysum(shortdate, filesize)
  2105.      char *shortdate;
  2106.      long int filesize;
  2107. {
  2108.     int weekday;
  2109.  
  2110.     weekday = getweekday(shortdate);
  2111.     weekday = (weekday - 1 == -1) ? 6 : weekday - 1;
  2112.  
  2113.     daysumstats[weekday] += 1;
  2114.     if (printbytes)
  2115.         daysumstats[weekday + 7] += filesize;
  2116. }
  2117.  
  2118. void analyzedaily(shortdate, filesize, islastline)
  2119.      char *shortdate;
  2120.      long int filesize;
  2121.      int islastline;
  2122. {
  2123.     int yearday;
  2124.     static int starting, prevyearday, dailyrequests;
  2125.     static long bytecount;
  2126.  
  2127.     yearday = getyearday(shortdate);
  2128.  
  2129.     if (!starting) {
  2130.         starting = 1;
  2131.         dailyreport = (struct node *) addnode(dailyreport, shortdate,
  2132.             -1, 0, 0, -1, "daily");
  2133.         bytecount += filesize;
  2134.         dailyrequests++;
  2135.         prevyearday = yearday;
  2136.         return;
  2137.     }
  2138.     if (yearday != prevyearday) {
  2139.         dailyreport = (struct node *) addnode(dailyreport, NULL,
  2140.             dailyrequests, 0, 0, bytecount, "daily");
  2141.         if (dailyrequests > largestdaynum)
  2142.             largestdaynum = dailyrequests;
  2143.         if (bytecount > largestdaynum)
  2144.             largestdaynum = bytecount;
  2145.         if (islastline)
  2146.             return;
  2147.         dailyreport = (struct node *) addnode(dailyreport, shortdate,
  2148.             -1, 0, 0, -1, "daily");
  2149.         dailyrequests = bytecount = 0;
  2150.     }
  2151.  
  2152.     if (islastline) {
  2153.         dailyreport = (struct node *) addnode(dailyreport, NULL,
  2154.             dailyrequests, 0, 0, bytecount, "daily");
  2155.         if (dailyrequests > largestdaynum)
  2156.             largestdaynum = dailyrequests;
  2157.         if (bytecount > largestdaynum)
  2158.             largestdaynum = bytecount;
  2159.     }
  2160.     else {
  2161.         prevyearday = yearday;
  2162.         bytecount += filesize;
  2163.         dailyrequests++;
  2164.     }
  2165. }
  2166.  
  2167. void analyzehoursum(date, filesize)
  2168.      char *date;
  2169.      long int filesize;
  2170. {
  2171.     int hour;
  2172.     char hourstr[3];
  2173.  
  2174.     sprintf(hourstr, "%c%c", (date[11] == ' ') ? '0' : date[11], date[12]);
  2175.     hour = atoi(hourstr);
  2176.  
  2177.     hoursumstats[hour] += 1;
  2178.     if (printbytes)
  2179.         hoursumstats[hour + 24] += filesize;
  2180. }
  2181.  
  2182. void analyzehourly(date, filesize, islastline)
  2183.      char *date;
  2184.      long int filesize;
  2185.      int islastline;
  2186. {
  2187.     char hourstr[3], shortdate[SHORTDATELEN];
  2188.     int yearday, hour;
  2189.     static int starting, prevhour, prevyearday, dailyrequests,
  2190.     hourlyrequests;
  2191.     static long bytecount;
  2192.  
  2193.     sprintf(hourstr, "%c%c", (date[11] == ' ') ? '0' : date[11], date[12]);
  2194.     hour = atoi(hourstr);
  2195.     convtoshortdate(date, shortdate);
  2196.     yearday = getyearday(shortdate);
  2197.  
  2198.     if (!starting) {
  2199.         starting = 1;
  2200.         hourlyreport = (struct node *) addnode(hourlyreport, shortdate,
  2201.             -1, hour, -1, -1, "hourly");
  2202.         bytecount += filesize;
  2203.         hourlyrequests++;
  2204.         dailyrequests++;
  2205.         prevhour = hour;
  2206.         prevyearday = yearday;
  2207.         return;
  2208.     }
  2209.     if (yearday != prevyearday) {
  2210.         hourlyreport = (struct node *)
  2211.         addnode(hourlyreport, NULL, hourlyrequests, -1,
  2212.         dailyrequests, bytecount, "hourly");
  2213.         if (islastline)
  2214.             return;
  2215.         hourlyreport = (struct node *) addnode(hourlyreport, shortdate,
  2216.             -1, hour, -1, -1, "hourly");
  2217.         hourlyrequests = bytecount = 0;
  2218.         dailyrequests = 0;
  2219.     }
  2220.     else if (hour != prevhour) {
  2221.         hourlyreport = (struct node *) addnode(hourlyreport, NULL,
  2222.             hourlyrequests, -1, -1, bytecount, "hourly");
  2223.         if (hourlyrequests > largesthournum)
  2224.             largesthournum = hourlyrequests;
  2225.         if (bytecount > largesthournum)
  2226.             largesthournum = bytecount;
  2227.         if (islastline)
  2228.             return;
  2229.         hourlyreport = (struct node *) addnode(hourlyreport, NULL,
  2230.             -1, hour, -1, -1, "hourly");
  2231.         hourlyrequests = bytecount = 0;
  2232.     }
  2233.  
  2234.     if (islastline) {
  2235.         hourlyreport = (struct node *) addnode(hourlyreport, NULL,
  2236.             hourlyrequests, -1, dailyrequests, bytecount, "hourly");
  2237.         if (hourlyrequests > largesthournum)
  2238.             largesthournum = hourlyrequests;
  2239.         if (bytecount > largesthournum)
  2240.             largesthournum = bytecount;
  2241.     }
  2242.     else {
  2243.         prevhour = hour;
  2244.         prevyearday = yearday;
  2245.         bytecount += filesize;
  2246.         hourlyrequests++;
  2247.         dailyrequests++;
  2248.     }
  2249. }
  2250.  
  2251. void printhour(hour)
  2252.      int hour;
  2253. {
  2254.     if (!hour)
  2255.         printf("  midnite: ");
  2256.     else if (hour == 12)
  2257.         printf("     noon: ");
  2258.     else
  2259.         printf(" %s%d:00 %s: ", ((hour > 9 && hour < 12) ||
  2260.         (hour > 21 && hour <= 23)) ? "" : " ",
  2261.         (hour > 12) ? hour - 12 : hour, (hour > 12) ? "pm" : "am");
  2262. }
  2263.  
  2264. int getcommondateaddress(logline, date, address, request, filesize)
  2265.      char *logline;
  2266.      char *date;
  2267.      char *address;
  2268.      char *request;
  2269.      long *filesize;
  2270. {
  2271.     int i, j, status, size;
  2272.     char *c, tmpdate[COMMONDATELEN];
  2273.  
  2274.     if (!isvalidreq(logline))
  2275.         return 0;
  2276.     if (strlen(logline) < COMMONDATELEN)
  2277.         return 0;
  2278.     if ((strchr(logline, '[') == NULL) || (strchr(logline, ']') == NULL))
  2279.         return 0;
  2280.     if (logline[0] == '-')
  2281.         return 0;
  2282.  
  2283.     for (i = 0; logline[i] != ' ' && logline[i] != '\t' && i < ADDRLEN; i++)
  2284.         address[i] = logline[i];
  2285.     address[i] = '\0';
  2286.  
  2287.     while (logline[i++] != '[')
  2288.         ;
  2289.  
  2290.     for (j = 0; logline[i] != ']' && j <= COMMONDATELEN; )
  2291.         tmpdate[j++] = logline[i++];
  2292.     tmpdate[j] = '\0';
  2293.  
  2294.     date[0] = 'x';
  2295.     date[1] = 'x';
  2296.     date[2] = 'x';
  2297.     date[3] = ' ';
  2298.     date[4] = tmpdate[3];
  2299.     date[5] = tmpdate[4];
  2300.     date[6] = tmpdate[5];
  2301.     date[7] = ' ';
  2302.     date[8] = tmpdate[0];
  2303.     date[9] = tmpdate[1];
  2304.     date[10] = ' ';
  2305.     date[11] = tmpdate[12];
  2306.     date[12] = tmpdate[13];
  2307.     date[13] = ':';
  2308.     date[14] = tmpdate[15];
  2309.     date[15] = tmpdate[16];
  2310.     date[16] = ':';
  2311.     date[17] = tmpdate[18];
  2312.     date[18] = tmpdate[19];
  2313.     date[19] = ' ';
  2314.     date[20] = tmpdate[7];
  2315.     date[21] = tmpdate[8];
  2316.     date[22] = tmpdate[9];
  2317.     date[23] = tmpdate[10];
  2318.     date[24] = '\0';
  2319.  
  2320. #ifdef GMTOFFSET
  2321.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2322. #endif
  2323.  
  2324.     c = (char *) headerend(logline);
  2325.     if (isspace(*c))
  2326.         c++;
  2327.     for (i = 0; *c && !isspace(*c) && *c != '?' && *c != '"'; c++)
  2328.         request[i++] = *c;
  2329.     request[i] = '\0';
  2330.     if (!i || !strcmp(request, "/"))
  2331.         strcpy(request, HOMEPAGE);
  2332.  
  2333.     c = (char *) strrchr(logline, '"') + 2;
  2334.     if (*c != '-') {
  2335.         status = 0;
  2336.         while (isdigit(*c)) {
  2337.             status = (status * 10) + (*c - '0');
  2338.             c++;
  2339.         }
  2340.         if (status < 200 || status > 299)
  2341.             return 0;
  2342.         c++;
  2343.     }
  2344.     else
  2345.         c += 2;
  2346.  
  2347.     size = 0;
  2348.     if (*c != '-') {
  2349.         while (isdigit(*c)) {
  2350.             size = (size * 10) + (*c - '0');
  2351.             c++;
  2352.         }
  2353.     }
  2354.     *filesize = (long) size;
  2355.  
  2356.     return 1;
  2357. }
  2358.  
  2359. int getcerndateaddress(logline, date, address, request)
  2360.      char *logline;
  2361.      char *date;
  2362.      char *address;
  2363.      char *request;
  2364. {
  2365.     int i, j;
  2366.     char *c;
  2367.  
  2368.     if (!isvalidreq(logline))
  2369.         return 0;
  2370.     if (strlen(logline) < DATELEN)
  2371.         return 0;
  2372.     if (!isupper(logline[0]) || logline[DATELEN - 1] != ' ')
  2373.         return 0;
  2374.  
  2375.     for (i = 0; i < DATELEN - 1; i++)
  2376.         date[i] = logline[i];
  2377.     date[i++] = '\0';
  2378.  
  2379. #ifdef GMTOFFSET
  2380.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2381. #endif
  2382.  
  2383.     for (j = 0; logline[i] == '.' || isdigit(logline[i]); i++)
  2384.         address[j++] = logline[i];
  2385.     address[j] = '\0';
  2386.  
  2387.     c = (char *) headerend(logline);
  2388.     if (isspace(*c))
  2389.         c++;
  2390.     for (i = 0; *c && !isspace(*c) && *c != '?'; c++)
  2391.         request[i++] = *c;
  2392.     request[i] = '\0';
  2393.     if (!i || !strcmp(request, "/"))
  2394.         strcpy(request, HOMEPAGE);
  2395.  
  2396.     return 1;
  2397. }
  2398.  
  2399. int getncsadateaddress(logline, date, address, request)
  2400.      char *logline;
  2401.      char *date;
  2402.      char *address;
  2403.      char *request;
  2404. {
  2405.     int i, j;
  2406.     char *c;
  2407.  
  2408.     if (!isvalidreq(logline))
  2409.         return 0;
  2410.     if ((strchr(logline, '[') == NULL) || (strchr(logline, ']') == NULL))
  2411.         return 0;
  2412.     if (strlen(logline) < DATELEN)
  2413.         return 0;
  2414.  
  2415.     for (i = 0; logline[i] != '[' && logline[i] != ' ' &&
  2416.     logline[i] != '\t' && i < ADDRLEN; i++)
  2417.         address[i] = logline[i];
  2418.     address[i] = '\0';
  2419.  
  2420.     while (logline[i++] != '[')
  2421.         ;
  2422.  
  2423.     for (j = 0; logline[i] != ']' && j <= DATELEN; )
  2424.         date[j++] = logline[i++];
  2425.     date[j] = '\0';
  2426.  
  2427. #ifdef GMTOFFSET
  2428.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2429. #endif
  2430.  
  2431.     c = (char *) headerend(logline);
  2432.     if (isspace(*c))
  2433.         c++;
  2434.     for (i = 0; *c && !isspace(*c) && *c != '?'; c++)
  2435.         request[i++] = *c;
  2436.     request[i] = '\0';
  2437.     if (!i || !strcmp(request, "/"))
  2438.         strcpy(request, HOMEPAGE);
  2439.  
  2440.     return 1;
  2441. }
  2442.  
  2443. int getplexdateaddress(logline, date, address, request)
  2444.      char *logline;
  2445.      char *date;
  2446.      char *address;
  2447.      char *request;
  2448. {
  2449.     int i, j;
  2450.     char *c;
  2451.  
  2452.     if (!isvalidreq(logline))
  2453.         return 0;
  2454.     if (logline[0] == '-')
  2455.         return 0;
  2456.     if (strlen(logline) < DATELEN)
  2457.         return 0;
  2458.  
  2459.     for (i = 0; logline[i] != ' ' && i < ADDRLEN; i++)
  2460.         address[i] = logline[i];
  2461.     address[i] = '\0';
  2462.  
  2463.     while (logline[i] == ' ')
  2464.         i++;
  2465.     for (j = 0; j < DATENOTZLEN; )
  2466.         date[j++] = logline[i++];
  2467.     i += TZLEN;
  2468.     for (i++; j < DATELEN - 1; )
  2469.         date[j++] = logline[i++];
  2470.     date[j] = '\0';
  2471.  
  2472. #ifdef GMTOFFSET
  2473.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2474. #endif
  2475.  
  2476.     c = (char *) headerend(logline);
  2477.     if (isspace(*c))
  2478.         c++;
  2479.     for (i = 0; *c && !isspace(*c) && *c != '?'; c++)
  2480.         request[i++] = *c;
  2481.     request[i] = '\0';
  2482.     if (!i || !strcmp(request, "/"))
  2483.         strcpy(request, HOMEPAGE);
  2484.  
  2485.     return 1;
  2486. }
  2487.  
  2488. int getgndateaddress(logline, date, address, request)
  2489.      char *logline;
  2490.      char *date;
  2491.      char *address;
  2492.      char *request;
  2493. {
  2494.     int i, j;
  2495.     char *c;
  2496.  
  2497. #ifdef GNREPORTALL
  2498.     if (strstr(logline, "Sent") == NULL && !isvalidreq(logline))
  2499. #else
  2500.     if (!isvalidreq(logline))
  2501. #endif
  2502.         return 0;
  2503.     if ((strchr(logline, '(') == NULL) || (strchr(logline, ')') == NULL))
  2504.         return 0;
  2505.     if (strlen(logline) < DATELEN)
  2506.         return 0;
  2507.  
  2508.     for (i = 0; logline[i] != ':' && i < ADDRLEN; i++)
  2509.         address[i] = logline[i];
  2510.     address[i] = '\0';
  2511.  
  2512.     i = strlen(logline) - 9;
  2513.     if (logline[i] == ':' && logline[i - 3] == ':')
  2514.         c = (char *) &logline[0] + strlen(logline) - DATELEN;
  2515.     else
  2516.         c = (char *) strchr(logline, ':') + 2;
  2517.     for (j = 0; j <= DATELEN; c++)
  2518.         date[j++] = *c;
  2519.     date[j] = '\0';
  2520.  
  2521. #ifdef GMTOFFSET
  2522.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2523. #endif
  2524.  
  2525.     c = (char *) headerend(logline);
  2526. #ifdef GNREPORTALL
  2527.     if (c == NULL) {
  2528.         c = (char *) strchr(logline, '(') + 1;
  2529.         if (c == NULL)
  2530.             return 0;
  2531.     }
  2532. #else
  2533.     if (c == NULL)
  2534.         return 0;
  2535. #endif
  2536.     if (isspace(*c))
  2537.         c++;
  2538.     for (i = 0; *c && *c != ')' && *c != '?' && !isspace(*c); c++)
  2539.         request[i++] = *c;
  2540.     request[i] = '\0';
  2541.  
  2542.     if (!i || !strcmp(request, "/"))
  2543.         strcpy(request, HOMEPAGE);
  2544.  
  2545.     return 1;
  2546. }
  2547.  
  2548. int getmacdateaddress(logline, date, address, request)
  2549.      char *logline;
  2550.      char *date;
  2551.      char *address;
  2552.      char *request;
  2553. {
  2554.     int i, j, monthnum;
  2555.     char *c, tmpdate[DATELEN];
  2556.  
  2557.     if (!strstr(logline, "OK"))
  2558.         return 0;
  2559.     if ((strchr(logline, ':') == NULL) || !isdigit(logline[0]))
  2560.         return 0;
  2561.     if (strlen(logline) < MACDATELEN)
  2562.         return 0;
  2563.  
  2564.     for (i = j = 0; logline[i] && !isspace(logline[i]); i++)
  2565.         tmpdate[j++] = logline[i];
  2566.     tmpdate[j++] = ' ';
  2567.     while (isspace(logline[i]))
  2568.         i++;
  2569.     for (; logline[i] && !isspace(logline[i]); i++)
  2570.         tmpdate[j++] = logline[i];
  2571.     tmpdate[j] = '\0';
  2572.     monthnum = ((tmpdate[0] - '0') * 10) + (tmpdate[1] - '0');
  2573.  
  2574.     date[0] = 'x';
  2575.     date[1] = 'x';
  2576.     date[2] = 'x';
  2577.     date[3] = ' ';
  2578.     date[4] = months[monthnum - 1][0];
  2579.     date[5] = months[monthnum - 1][1];
  2580.     date[6] = months[monthnum - 1][2];
  2581.     date[7] = ' ';
  2582.     date[8] = tmpdate[3];
  2583.     date[9] = tmpdate[4];
  2584.     date[10] = ' ';
  2585.     date[11] = tmpdate[9];
  2586.     date[12] = tmpdate[10];
  2587.     date[13] = ':';
  2588.     date[14] = tmpdate[12];
  2589.     date[15] = tmpdate[13];
  2590.     date[16] = ':';
  2591.     date[17] = tmpdate[15];
  2592.     date[18] = tmpdate[16];
  2593.     date[19] = ' ';
  2594.     date[20] = CENTURYSTR[0];
  2595.     date[21] = CENTURYSTR[1];
  2596.     date[22] = tmpdate[6];
  2597.     date[23] = tmpdate[7];
  2598.     date[24] = '\0';
  2599.  
  2600. #ifdef GMTOFFSET
  2601.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2602. #endif
  2603.  
  2604.     while (isspace(logline[i]))
  2605.         i++;
  2606.     while (!isspace(logline[i]))
  2607.         i++;
  2608.     while (isspace(logline[i]))
  2609.         i++;
  2610.  
  2611.     for (j = 0; logline[i] && logline[i] != '\n' &&
  2612.     !isspace(logline[i]); i++)
  2613.         address[j++] = logline[i];
  2614.     address[--j] = '\0';
  2615.  
  2616.     while (logline[i] == '.' || isspace(logline[i]))
  2617.         i++;
  2618.  
  2619.     for (j = 0; logline[i] && logline[i] != '\n'; i++)
  2620.         request[j++] = ((logline[i] == ':') ? '/' : logline[i]);
  2621.     request[j] = '\0';
  2622.  
  2623.     if (!i || !strcmp(request, "/"))
  2624.         strcpy(request, HOMEPAGE);
  2625.  
  2626.     return 1;
  2627. }
  2628.  
  2629. int getgophdateaddress(logline, date, address, request)
  2630.      char *logline;
  2631.      char *date;
  2632.      char *address;
  2633.      char *request;
  2634. {
  2635.     int i, j;
  2636.     char *c, *d;
  2637.  
  2638.     if (strchr(logline, ':') == NULL)
  2639.         return 0;
  2640.     if (strlen(logline) < DATELEN)
  2641.         return 0;
  2642.     if (!isupper(logline[0]) || logline[DATELEN - 1] != ' ')
  2643.         return 0;
  2644.  
  2645.     for (i = 0; i < DATELEN - 1; i++)
  2646.         date[i] = logline[i];
  2647.     date[i++] = '\0';
  2648.  
  2649. #ifdef GMTOFFSET
  2650.     strcpy(date, getdatestr(convtoyearsecs(date) + GMTOFFSET, 1));
  2651. #endif
  2652.  
  2653.     while (!isspace(logline[i++]))
  2654.         ;
  2655.     for (j = 0; logline[i] && logline[i] != ' '; i++)
  2656.         address[j++] = logline[i];
  2657.     address[j] = '\0';
  2658.  
  2659.     if (strstr(logline, "search ")) {
  2660.         c = (char *) strstr(logline, "search ") + 7;
  2661.         d = (char *) strstr(logline, " for");
  2662.     }
  2663.     else if (strstr(logline, "range ")) {
  2664.         c = (char *) strstr(logline, "of file ") + 8;
  2665.         d = c + strlen(logline);
  2666.     }
  2667.     else if (strstr(logline, "retrieved")) {
  2668.         c = (char *) strchr(logline, '/');
  2669.         d = c + strlen(logline);
  2670.     }
  2671.     else if (strstr(logline, "Root Connection")) {
  2672.         c = (char *) strstr(logline, "Root Connection");
  2673.         d = c + strlen(logline);
  2674.     }
  2675.     else
  2676.         return 0;
  2677.  
  2678.     if (c == NULL)
  2679.         return 0;
  2680.     for (i = 0; *c && c != d; c++)
  2681.         request[i++] = *c;
  2682.     request[i] = '\0';
  2683.  
  2684.     if (request[strlen(request) - 1] == '\n')
  2685.         request[strlen(request) - 1] = '\0';
  2686.  
  2687.     return 1;
  2688. }
  2689.  
  2690. void getdomain(address, date, level, filesize)
  2691.      char *address;
  2692.      long int date;
  2693.      int level;
  2694.      long int filesize;
  2695. {
  2696.     int i, maxlevel;
  2697.     char *s, *t, domain[DOMAINLEN], tempdomain[DOMAINLEN];
  2698.  
  2699. #ifndef SHOWIPDOMAINS
  2700.     if (isip(address)) {
  2701.         addhashdn(address);
  2702.         address = IPDOMSTR;
  2703.         adddomainentry(domainlist, address, date, filesize);
  2704.         return;
  2705.     }
  2706. #endif
  2707.  
  2708.     if (!strchr(address, '.')) {
  2709.         domainlist = (struct domainentry *)
  2710.         adddomainentry(domainlist, address, date, filesize);
  2711.         addhashdn(address);
  2712.         return;
  2713.     }
  2714.  
  2715.     domain[0] = '\0';
  2716.     maxlevel = numstrchr(address, '.') + 1;
  2717.     while (1) {
  2718.         t = (char *) strdup(address);
  2719.         if (!maxlevel)
  2720.             break;
  2721.         for (i = 0; i < maxlevel; i++)
  2722.             s = (char *) strtok((i) ? NULL : t, ".");
  2723.         if (s == NULL)
  2724.             break;
  2725.         sprintf(tempdomain, "%s.%s", domain, s);
  2726.         strcpy(domain, tempdomain);
  2727.  
  2728.         if (level-- > 0)
  2729.             domainlist = (struct domainentry *)
  2730.             adddomainentry(domainlist, domain, date, filesize);
  2731.  
  2732.         maxlevel--;
  2733.         free(t);
  2734.     }
  2735.     addhashdn(domain);
  2736. }
  2737.  
  2738. char *getweekdatemask(month, day, year)
  2739.      int month;
  2740.      int day;
  2741.      int year;
  2742. {
  2743.     static char datemask[MASKLEN], shortdate[SHORTDATELEN],
  2744.         monshortdate[SHORTDATELEN], sunshortdate[SHORTDATELEN];
  2745.     int monmonth, monday, monyear, sunmonth, sunday, sunyear;
  2746.  
  2747.     sprintf(shortdate, "%02d/%02d/%02d", month, day, year);
  2748.  
  2749.     strcpy(monshortdate, getshortdate(shortdate, 1));
  2750.     strcpy(sunshortdate, getshortdate(shortdate, 0));
  2751.     sscanf(monshortdate, "%d/%d/%d", &monmonth, &monday, &monyear);
  2752.     sscanf(sunshortdate, "%d/%d/%d", &sunmonth, &sunday, &sunyear);
  2753.  
  2754.     sprintf(datemask, "[%d-%d]/[%d-%d]/[%d-%d]", monmonth, (sunmonth >
  2755.     monmonth) ? sunmonth : monmonth, monday, (sunday > monday) ? sunday :
  2756.     monday, monyear, (sunyear > monyear) ? sunyear : monyear);
  2757.  
  2758.     return datemask;
  2759. }
  2760.  
  2761. void convtoshortdate(date, shortdate)
  2762.      char *date;
  2763.      char *shortdate;
  2764. {
  2765.     int i, month;
  2766.  
  2767.     for (i = 0; strstr(date, months[i]) == NULL; i++)
  2768.         ;
  2769.     month = i + 1;
  2770.     sprintf(shortdate, "%02d/%c%c/%c%c", month, (date[8] == ' ') ?
  2771.     '0' : date[8], date[9], date[22], date[23]);
  2772. }
  2773.  
  2774. char *convtoeurodate(shortdate)
  2775.      char *shortdate;
  2776. {
  2777. #ifndef EURODATE
  2778.     return shortdate;
  2779. #else
  2780.     static char tmpdate[SHORTDATELEN];
  2781.  
  2782.     strcpy(tmpdate, shortdate);
  2783.     tmpdate[0] = shortdate[3];
  2784.     tmpdate[1] = shortdate[4];
  2785.     tmpdate[3] = shortdate[0];
  2786.     tmpdate[4] = shortdate[1];
  2787.  
  2788.     return tmpdate;
  2789. #endif
  2790. }
  2791.  
  2792. int convtoyearsecs(date)
  2793.      char *date;
  2794. {
  2795.     char hourstr[3], minstr[3], secstr[3], shortdate[SHORTDATELEN];
  2796.     int hours, minutes, seconds;
  2797.     long yearsecs;
  2798.  
  2799.     convtoshortdate(date, shortdate);
  2800.     yearsecs = getyearsecs(shortdate);
  2801.  
  2802.     sprintf(hourstr, "%c%c", date[11], date[12]);
  2803.     sprintf(minstr, "%c%c", date[14], date[15]);
  2804.     sprintf(secstr, "%c%c", date[17], date[18]);
  2805.  
  2806.     hours = atoi(hourstr);
  2807.     minutes = atoi(minstr);
  2808.     seconds = atoi(secstr);
  2809.  
  2810.     return (int) (yearsecs + (hours * SECSPERHOUR) +
  2811.     (minutes * SECSPERMIN) + seconds);
  2812. }
  2813.  
  2814. unsigned hash(s)
  2815.      char *s;
  2816. {
  2817.     unsigned hashval;
  2818.  
  2819.     for (hashval = 0; *s != '\0'; s++)
  2820.         hashval = *s + 31 * hashval;
  2821.     return hashval % HASHSIZE;
  2822. }
  2823.  
  2824. void addhash(nameaddress, numaddress)
  2825.      char *nameaddress;
  2826.      char *numaddress;
  2827. {
  2828.     struct hosttable *hp;
  2829.     unsigned hashval;
  2830.  
  2831.     hp = (struct hosttable *) emalloc(sizeof(*hp));
  2832.     hp->numaddress = strdup(numaddress);
  2833.     hashval = hash(numaddress);
  2834.     hp->next = addrtable[hashval];
  2835.     addrtable[hashval] = hp;
  2836.     hp->nameaddress = strdup(nameaddress);
  2837. }
  2838.  
  2839. char *hashlookupnumaddr(numaddress)
  2840.      char *numaddress;
  2841. {
  2842.     struct hosttable *hp;
  2843.  
  2844.     for (hp = addrtable[hash(numaddress)]; hp != NULL; hp = hp->next)
  2845.         if (strcmp(numaddress, hp->numaddress) == 0)
  2846.             return hp->nameaddress;
  2847.     return NULL;
  2848. }
  2849.  
  2850. void addhashsize(filesize, request)
  2851.      long int filesize;
  2852.      char *request;
  2853. {
  2854.     struct sizetable *sp;
  2855.     unsigned hashval;
  2856.  
  2857.     sp = (struct sizetable *) emalloc(sizeof(*sp));
  2858.     sp->request = strdup(request);
  2859.     hashval = hash(request);
  2860.     sp->next = reqtable[hashval];
  2861.     reqtable[hashval] = sp;
  2862.     sp->filesize = filesize;
  2863. }
  2864.  
  2865. long hashlookupsize(request)
  2866.      char *request;
  2867. {
  2868.     struct sizetable *sp;
  2869.  
  2870.     for (sp = reqtable[hash(request)]; sp != NULL; sp = sp->next)
  2871.         if (strcmp(request, sp->request) == 0)
  2872.             return sp->filesize;
  2873.     return -1;
  2874. }
  2875.  
  2876. void addtreeentry(request, date, filesize)
  2877.      char *request;
  2878.      long int date;
  2879.      long int filesize;
  2880. {
  2881.     int i;
  2882.     char *s, *t, path[REQUESTLEN], tempstr[REQUESTLEN];
  2883.  
  2884.     i = 0;
  2885.     t = (char *) strdup(request);
  2886.  
  2887.     path[0] = '\0';
  2888.     while (1) {
  2889.         s = (char *) strtok((i++) ? NULL : t, "/");
  2890.         if (s == NULL)
  2891.             break;
  2892.         sprintf(tempstr, "%s/%s", path, s);
  2893.         strcpy(path, tempstr);
  2894.         addhashreq(path, date, filesize);
  2895.     }
  2896.     free(t);
  2897. }
  2898.  
  2899. void addhashreq(request, date, filesize)
  2900.      char *request;
  2901.      long int date;
  2902.      long int filesize;
  2903. {
  2904.     struct requesttable *rt;
  2905.     unsigned hashval;
  2906.  
  2907.     for (rt = treetable[hash(request)]; rt != NULL; rt = rt->next)
  2908.         if (strcmp(request, rt->request) == 0) {
  2909.             rt->date = date;
  2910.             rt->requestnum++;
  2911.             if (rt->requestnum > largetreereqnum)
  2912.                 largetreereqnum = rt->requestnum;
  2913.             rt->filesize += filesize;
  2914.             if (rt->filesize > largetreebytenum)
  2915.                 largetreebytenum = rt->filesize;
  2916.             return;
  2917.         }
  2918.  
  2919.     rt = (struct requesttable *) emalloc(sizeof(*rt));
  2920.     rt->request = strdup(request);
  2921.     hashval = hash(request);
  2922.     rt->next = treetable[hashval];
  2923.     treetable[hashval] = rt;
  2924.     rt->date = date;
  2925.     rt->filesize = filesize;
  2926.     rt->requestnum = 1;
  2927. }
  2928.  
  2929. int hashlookupreq(request, date, filesize, requestnum)
  2930.      char *request;
  2931.      long int *date;
  2932.      long int *filesize;
  2933.      long int *requestnum;
  2934. {
  2935.     struct requesttable *rt;
  2936.  
  2937.     for (rt = treetable[hash(request)]; rt != NULL; rt = rt->next)
  2938.         if (strcmp(request, rt->request) == 0) {
  2939.             if (rt->removed == 1)
  2940.                 return 0;
  2941.             *date = rt->date;
  2942.             *filesize = rt->filesize;
  2943.             *requestnum = rt->requestnum;
  2944.             return 1;
  2945.         }
  2946.     *date = -1;
  2947.     *filesize = 0;
  2948.     *requestnum = 0;
  2949.     return 0;
  2950. }
  2951.  
  2952. void hashremreq(request)
  2953.      char *request;
  2954. {
  2955.     struct requesttable *rt;
  2956.  
  2957.     for (rt = treetable[hash(request)]; rt != NULL; rt = rt->next)
  2958.         if (strcmp(request, rt->request) == 0) {
  2959.             rt->removed = 1;
  2960.             return;
  2961.         }
  2962. }
  2963.  
  2964. void installdomaintable(domainfile)
  2965.      char *domainfile;
  2966. {
  2967.     int i, j;
  2968.     char domline[DOMLINELEN], domain[DOMLEN], description[DOMDESCLEN];
  2969.     FILE *dfp;
  2970.  
  2971.     if ((dfp = fopen(domainfile, "r")) == NULL)
  2972.         progerr("Couldn't open domain code file.");
  2973.  
  2974.     while (fgets(domline, DOMLINELEN, dfp) != NULL) {
  2975.         if (isspace(domline[0]))
  2976.             continue;
  2977.         domain[0] = '.';
  2978.         for (i = 0, j = 1; !isspace(domline[i]); i++)
  2979.             domain[j++] = tolower(domline[i]);
  2980.         domain[j] = '\0';
  2981.         while (isspace(domline[i]))
  2982.             i++;
  2983.         for (j = 0; domline[i] && domline[i] != '\n'; i++)
  2984.             description[j++] = domline[i];
  2985.         description[j] = '\0';
  2986.         addhashdom(domain, description);
  2987.     }
  2988.  
  2989.     fclose(dfp);
  2990. }
  2991.  
  2992. void addhashdom(domain, description)
  2993.      char *domain;
  2994.      char *description;
  2995. {
  2996.     struct domaintable *dp;
  2997.     unsigned hashval;
  2998.  
  2999.     dp = (struct domaintable *) emalloc(sizeof(*dp));
  3000.     dp->domain = strdup(domain);
  3001.     hashval = hash(domain);
  3002.     dp->next = domtable[hashval];
  3003.     domtable[hashval] = dp;
  3004.     dp->description = strdup(description);
  3005. }
  3006.  
  3007. char *hashlookupdom(domain)
  3008.      char *domain;
  3009. {
  3010.     struct domaintable *dp;
  3011.  
  3012.     for (dp = domtable[hash(domain)]; dp != NULL; dp = dp->next)
  3013.         if (strcmp(domain, dp->domain) == 0)
  3014.             return dp->description;
  3015.     return NULL;
  3016. }
  3017.  
  3018. void addhashdn(domain)
  3019.      char *domain;
  3020. {
  3021.     struct dnametable *dp;
  3022.     unsigned hashval;
  3023.  
  3024.     if (hashlookupdn(domain))
  3025.         return;
  3026.  
  3027.     dp = (struct dnametable *) emalloc(sizeof(*dp));
  3028.     dp->domain = strdup(domain);
  3029.     hashval = hash(domain);
  3030.     dp->next = dntable[hashval];
  3031.     dntable[hashval] = dp;
  3032. }
  3033.  
  3034. int hashlookupdn(domain)
  3035.      char *domain;
  3036. {
  3037.     struct dnametable *dp;
  3038.  
  3039.     for (dp = dntable[hash(domain)]; dp != NULL; dp = dp->next)
  3040.         if (strcmp(domain, dp->domain) == 0)
  3041.             return 1;
  3042.     return 0;
  3043. }
  3044.  
  3045. int hashuniqdn(domain)
  3046.      char *domain;
  3047. {
  3048.     int i, hits;
  3049.     struct dnametable *dp;
  3050.  
  3051.     for (i = hits = 0; i < HASHSIZE; i++)
  3052.         for (dp = dntable[i]; dp != NULL; dp = dp->next) {
  3053. #ifndef SHOWIPDOMAINS
  3054.             if (strcmp(domain, IPDOMSTR) == 0 &&
  3055.             isip(dp->domain)) {
  3056.                 hits++;
  3057.                 continue;
  3058.             }
  3059. #endif
  3060.             if ((char *) strstr(dp->domain, domain) == (char *)
  3061.             dp->domain)
  3062.                 hits++;
  3063.         }
  3064.     return hits;
  3065. }
  3066.  
  3067. struct entry *addentry(e, address, date, islastweek, filesize)
  3068.      struct entry *e;
  3069.      char *address;
  3070.      long int date;
  3071.      int islastweek;
  3072.      long int filesize;
  3073. {
  3074.     int isbigger, isequal;
  3075.  
  3076.     isbigger = isequal = 0;
  3077.     if (e == NULL) {
  3078.         e = (struct entry *) emalloc(sizeof(struct entry));
  3079.         e->docnum = 1;
  3080.         e->address = (char *) strdup(address);
  3081.         e->date = date;
  3082.         e->filesize = filesize;
  3083.         e->left = e->right = NULL;
  3084.         uniquehostnum++;
  3085.         if (islastweek == 1)
  3086.             lastweekshosts++;
  3087.         return e;
  3088.     }
  3089.  
  3090.     isbigger = (strcmp(address, e->address) > 0) ? 1 : 0;
  3091.     if (!strcmp(address, e->address))
  3092.         isequal = 1;
  3093.  
  3094.     if (isequal) {
  3095.         e->filesize += filesize;
  3096.         e->date = date;
  3097.         e->docnum += 1;
  3098.     }
  3099.     else if (isbigger)
  3100.         e->left = addentry(e->left, address,
  3101.         date, islastweek, filesize);
  3102.     else
  3103.         e->right = addentry(e->right, address,
  3104.         date, islastweek, filesize);
  3105.  
  3106.     return e;
  3107. }
  3108.  
  3109. struct entry *addsortentry(e, address, date, docnum, filesize)
  3110.      struct entry *e;
  3111.      char *address;
  3112.      long int date;
  3113.      int docnum;
  3114.      long int filesize;
  3115. {
  3116.     int i, j, isbigger;
  3117.  
  3118.     if (e == NULL) {
  3119.         e = (struct entry *) emalloc(sizeof(struct entry));
  3120.         e->docnum = docnum;
  3121.         e->address = (char *) strdup(address);
  3122.         e->filesize = filesize;
  3123.         e->date = date;
  3124.         e->left = e->right = NULL;
  3125.     }
  3126.     else {
  3127.         if (!strcmp(full_report, "FULLADDR")) {
  3128.             i = isip(address);
  3129.             j = isip(e->address);
  3130.             if (i && j)
  3131.                 isbigger = (addrcmp(address, e->address)
  3132.                 > 0) ? 1 : 0;
  3133.             else if (i || j)
  3134.                 isbigger = (i) ? 1 : 0;
  3135.             else
  3136.                 isbigger = (strcmp(address, e->address)
  3137.                 > 0) ? 1 : 0;
  3138.         }
  3139.         else if (!strcmp(full_report, "FULLACCESS")) {
  3140.             isbigger = (docnum < e->docnum) ? 1 : 0;
  3141.             if (docnum == e->docnum)
  3142.                 isbigger = (date < e->date) ? 1 : 0;
  3143.         }
  3144.         else if (!strcmp(full_report, "FULLDATE")) {
  3145.             isbigger = (date < e->date) ? 1 : 0;
  3146.             if (date == e->date)
  3147.                 isbigger = (docnum < e->docnum) ? 1 : 0;
  3148.         }
  3149.         else if (!strcmp(full_report, "FULLBYTES")) {
  3150.             isbigger = (filesize < e->filesize) ? 1 : 0;
  3151.             if (filesize == e->filesize)
  3152.                 isbigger = (date < e->date) ? 1 : 0;
  3153.         }
  3154.  
  3155.         if (isbigger)
  3156.             e->left = addsortentry(e->left, address,
  3157.             date, docnum, filesize);
  3158.         else
  3159.             e->right = addsortentry(e->right, address,
  3160.             date, docnum, filesize);
  3161.     }
  3162.  
  3163.     return e;
  3164. }
  3165.  
  3166. struct requestentry *addrequestentry(e, request, date, filesize)
  3167.      struct requestentry *e;
  3168.      char *request;
  3169.      long int date;
  3170.      long int filesize;
  3171. {
  3172.     if (e == NULL) {
  3173.         e = (struct requestentry *)
  3174.         emalloc(sizeof(struct requestentry));
  3175.         e->request = (char *) strdup(request);
  3176.         e->date = date;
  3177.         e->requestnum = 1;
  3178.         e->filesize = filesize;
  3179.         e->requestsize = filesize;
  3180.         e->left = e->right = NULL;
  3181.     }
  3182.     else if (strcmp(request, e->request) > 0)
  3183.         e->left = addrequestentry(e->left, request, date, filesize);
  3184.     else if (strcmp(request, e->request) < 0)
  3185.         e->right = addrequestentry(e->right, request, date, filesize);
  3186.     else {
  3187.         e->date = date;
  3188.         e->requestsize += filesize;
  3189.         e->requestnum += 1;
  3190.     }
  3191.  
  3192.     return e;
  3193. }
  3194.  
  3195. struct requestentry *addsortrequestentry(e, request, date, requestnum, filesize, requestsize)
  3196.      struct requestentry *e;
  3197.      char *request;
  3198.      long int date;
  3199.      int requestnum;
  3200.      long int filesize;
  3201.      long int requestsize;
  3202. {
  3203.     int isbigger;
  3204.  
  3205.     if (e == NULL) {
  3206.         e = (struct requestentry *)
  3207.         emalloc(sizeof(struct requestentry));
  3208.         e->request = (char *) strdup(request);
  3209.         e->date = date;
  3210.         e->filesize = filesize;
  3211.         e->requestsize = requestsize;
  3212.         e->requestnum = requestnum;
  3213.         e->left = e->right = NULL;
  3214.     }
  3215.     else {
  3216.         if (!strcmp(request_report, "REQUEST"))
  3217.             isbigger = (strcmp(request, e->request) > 0) ? 1 : 0;
  3218.         else if (!strcmp(request_report, "REQACCESS")) {
  3219.             isbigger = (requestnum < e->requestnum) ? 1 : 0;
  3220.             if (requestnum == e->requestnum)
  3221.                 isbigger = (date < e->date) ? 1 : 0;
  3222.         }
  3223.         else if (!strcmp(request_report, "REQDATE")) {
  3224.             isbigger = (date < e->date) ? 1 : 0;
  3225.             if (date == e->date)
  3226.                 isbigger = (requestnum < e->requestnum) ? 1 : 0;
  3227.         }
  3228.         else if (!strcmp(request_report, "REQBYTES")) {
  3229.             isbigger = (requestsize < e->requestsize) ? 1 : 0;
  3230.             if (requestsize == e->requestsize)
  3231.                 isbigger = (strcmp(request, e->request) > 0) ?
  3232.                 1 : 0;
  3233.         }
  3234.         else if (!strcmp(request_report, "REQFILE")) {
  3235.             isbigger = (filesize < e->filesize) ? 1 : 0;
  3236.             if (filesize == e->filesize)
  3237.                 isbigger = (strcmp(request, e->request) > 0) ?
  3238.                 1 : 0;
  3239.         }
  3240.  
  3241.         if (isbigger)
  3242.             e->left = addsortrequestentry(e->left, request, date,
  3243.             requestnum, filesize, requestsize);
  3244.         else
  3245.             e->right = addsortrequestentry(e->right, request,
  3246.             date, requestnum, filesize, requestsize);
  3247.     }
  3248.  
  3249.     return e;
  3250. }
  3251.  
  3252. struct domainentry *adddomainentry(e, domain, date, filesize)
  3253.      struct domainentry *e;
  3254.      char *domain;
  3255.      long int date;
  3256.      long int filesize;
  3257. {
  3258.     if (e == NULL) {
  3259.         e = (struct domainentry *)
  3260.         emalloc(sizeof(struct domainentry));
  3261.         e->domain = (char *) strdup(domain);
  3262.         e->date = date;
  3263.         e->filesize = filesize;
  3264.         e->requestnum = 1;
  3265.         e->left = e->right = NULL;
  3266.     }
  3267.     else if (strcmp(domain, e->domain) > 0)
  3268.         e->left = adddomainentry(e->left, domain, date, filesize);
  3269.     else if (strcmp(domain, e->domain) < 0)
  3270.         e->right = adddomainentry(e->right, domain, date, filesize);
  3271.     else {
  3272.         e->date = date;
  3273.         e->filesize += filesize;
  3274.         e->requestnum += 1;
  3275.     }
  3276.  
  3277.     return e;
  3278. }
  3279.  
  3280. struct domainentry *addsortdomainentry(e, domain, date, requestnum, filesize, unique)
  3281.      struct domainentry *e;
  3282.      char *domain;
  3283.      long int date;
  3284.      int requestnum;
  3285.      long int filesize;
  3286.      int unique;
  3287. {
  3288.     int isbigger;
  3289.  
  3290.     if (e == NULL) {
  3291.         e = (struct domainentry *)
  3292.         emalloc(sizeof(struct domainentry));
  3293.         e->domain = (char *) strdup(domain);
  3294.         e->date = date;
  3295.         e->filesize = filesize;
  3296.         e->requestnum = requestnum;
  3297.         e->unique = unique;
  3298.         e->left = e->right = NULL;
  3299.     }
  3300.     else {
  3301.         if (!strcmp(domain_report, "DOMAIN"))
  3302.             isbigger = (strcmp(domain, e->domain) > 0) ? 1 : 0;
  3303.         else if (!strcmp(domain_report, "DOMACCESS")) {
  3304.             isbigger = (requestnum < e->requestnum) ? 1 : 0;
  3305.             if (requestnum == e->requestnum)
  3306.                 isbigger = (date < e->date) ? 1 : 0;
  3307.         }
  3308.         else if (!strcmp(domain_report, "DOMDATE")) {
  3309.             isbigger = (date < e->date) ? 1 : 0;
  3310.             if (date == e->date)
  3311.                 isbigger = (requestnum < e->requestnum) ? 1 : 0;
  3312.         }
  3313.         else if (!strcmp(domain_report, "DOMBYTES")) {
  3314.             isbigger = (filesize < e->filesize) ? 1 : 0;
  3315.             if (filesize == e->filesize)
  3316.                 isbigger = (strcmp(domain, e->domain) > 0) ?
  3317.                 1 : 0;
  3318.         }
  3319.         else if (!strcmp(domain_report, "DOMUNIQ")) {
  3320.             isbigger = (unique < e->unique) ? 1 : 0;
  3321.             if (unique == e->unique)
  3322.                 isbigger = (strcmp(domain, e->domain) > 0) ?
  3323.                 1 : 0;
  3324.         }
  3325.  
  3326.         if (isbigger)
  3327.             e->left = addsortdomainentry(e->left, domain, date,
  3328.             requestnum, filesize, unique);
  3329.         else
  3330.             e->right = addsortdomainentry(e->right, domain,
  3331.             date, requestnum, filesize, unique);
  3332.     }
  3333.  
  3334.     return e;
  3335. }
  3336.  
  3337. void sortreport(e)
  3338.      struct entry *e;
  3339. {
  3340.     if (e != NULL) {
  3341.         sortreport(e->right);
  3342.         if (e->filesize > largestbytenum)
  3343.             largestbytenum = e->filesize;
  3344.         if (e->docnum > largestdocnum)
  3345.             largestdocnum = e->docnum;
  3346.         sortedlist = (struct entry *)
  3347.         addsortentry(sortedlist, e->address,
  3348.         e->date, e->docnum, e->filesize);
  3349.         sortreport(e->left);
  3350.     }
  3351. }
  3352.  
  3353. void printreport(e, docfieldlen, bytefieldlen)
  3354.      struct entry *e;
  3355.      int docfieldlen;
  3356.      int bytefieldlen;
  3357. {
  3358.     int i;
  3359.     char date[LONGDATELEN];
  3360.     static int j;
  3361.  
  3362.     if (e != NULL) {
  3363.         printreport(e->right, docfieldlen, bytefieldlen);
  3364.         if (toplines && j++ >= toplines)
  3365.             return;
  3366.         i = docfieldlen - numlen(e->docnum) - 1;
  3367.         while (i-- > 0)
  3368.             putchar(' ');
  3369. #ifdef SHOWSECONDS
  3370.         strcpy(date, getdatestr(e->date, 2));
  3371.         printf("%d : %s :", e->docnum, date);
  3372. #else
  3373.         strcpy(date, getdatestr(e->date, 3));
  3374.         printf("%d : %s :", e->docnum, date);
  3375. #endif
  3376.         if (printbytes) {
  3377.             i = bytefieldlen - numlen(e->filesize);
  3378.             if (i < 0)
  3379.                 i = 1;
  3380.             while (i-- > 0)
  3381.                 putchar(' ');
  3382.             printf("%d :", e->filesize);
  3383.         }
  3384.         printf(" %s\n", e->address);
  3385.         fflush(stdout);
  3386.         printreport(e->left, docfieldlen, bytefieldlen);
  3387.     }
  3388. }
  3389.  
  3390. struct node *addnode(n, shortdate, requests, hour, total, filesize, type)
  3391.      struct node *n;
  3392.      char *shortdate;
  3393.      int requests;
  3394.      int hour;
  3395.      int total;
  3396.      long int filesize;
  3397.      char *type;
  3398. {
  3399.     struct node *tempnode, *newnode;
  3400.  
  3401.     newnode = (struct node *) emalloc(sizeof(struct node));
  3402.     newnode->shortdate = (shortdate != NULL) ?
  3403.     (char *) strdup(shortdate) : NULL;
  3404.     newnode->requests = (requests >= 0) ? requests : -1;
  3405.     newnode->filesize = (filesize >= 0) ? filesize : -1;
  3406.     if (!strcmp(type, "hourly")) {
  3407.         newnode->hour = (hour >= 0) ? hour : -1;
  3408.         newnode->total = (total >= 0) ? total : -1;
  3409.     }
  3410.     newnode->next = NULL;
  3411.  
  3412.     if (n == NULL)
  3413.         n = newnode;
  3414.     else {
  3415.         for (tempnode = n; tempnode->next != NULL; tempnode =
  3416.         tempnode->next)
  3417.             ;
  3418.         tempnode->next = newnode;
  3419.     }
  3420.  
  3421.     return n;
  3422. }
  3423.  
  3424. struct errorlist *adderror(e, error)
  3425.      struct errorlist *e;
  3426.      char *error;
  3427. {
  3428.     struct errorlist *tempnode, *newnode;
  3429.  
  3430.     newnode = (struct errorlist *) emalloc(sizeof(struct errorlist));
  3431.     newnode->error = (char *) strdup(error);
  3432.     newnode->next = NULL;
  3433.  
  3434.     if (e == NULL)
  3435.         e = newnode;
  3436.     else {
  3437.         for (tempnode = e; tempnode->next != NULL; tempnode =
  3438.         tempnode->next)
  3439.             ;
  3440.         tempnode->next = newnode;
  3441.     }
  3442.  
  3443.     return e;
  3444. }
  3445.  
  3446. void printerrors(e, fp)
  3447.      struct errorlist *e;
  3448.      FILE *fp;
  3449. {
  3450.     while (e != NULL) {
  3451.         fprintf(fp, "%s", e->error);
  3452.         e = e->next;
  3453.     }
  3454. }
  3455.  
  3456. void printsummary(type)
  3457.      char *type;
  3458. {
  3459.     int i, endnum;
  3460.     long largenum;
  3461.  
  3462.     if (!strcmp(type, "hourly"))
  3463.         endnum = 23;
  3464.     else
  3465.         endnum = 6;
  3466.  
  3467.     for (i = largenum = 0; i <= endnum; i++)
  3468.         if (!strcmp(type, "hourly")) {
  3469.             if (hoursumstats[i] > largenum)
  3470.                 largenum = hoursumstats[i];
  3471.             if (printbytes && hoursumstats[i + 24] > largenum)
  3472.                 largenum = hoursumstats[i + 24];
  3473.         }
  3474.         else {
  3475.             if (daysumstats[i] > largenum)
  3476.                 largenum = daysumstats[i];
  3477.             if (printbytes && daysumstats[i + 7] > largenum)
  3478.                 largenum = daysumstats[i + 7];
  3479.         }
  3480.         
  3481.     for (i = 0; i <= endnum; i++)
  3482.         if (!strcmp(type, "hourly")) {
  3483.             printhour(i);
  3484.             printgraph(11, hoursumstats[i], HOURSUMMARK, MARK,
  3485.             largenum);
  3486.             if (printbytes) {
  3487.                 printf("   bytes : ");
  3488.                 printgraph(11, hoursumstats[i + 24],
  3489.                 HOURSUMBYTEMARK, BYTEMARK, largenum);
  3490.             }
  3491.         }
  3492.         else {
  3493.             printf("   %s: ", days[(i == 6) ? 0 : i + 1]);
  3494.             printgraph(8, daysumstats[i], DAYSUMMARK, MARK,
  3495.             largenum);
  3496.             if (printbytes) {
  3497.                 printf("bytes : ");
  3498.                 printgraph(8, daysumstats[i + 7],
  3499.                 DAYSUMBYTEMARK, BYTEMARK, largenum);
  3500.             }
  3501.         }
  3502. }
  3503.  
  3504. void printgraphreport(n, type)
  3505.      struct node *n;
  3506.      char *type;
  3507. {
  3508.     while (n != NULL) {
  3509.         if (!strcmp(type, "monthly")) {
  3510.             if (n->shortdate != NULL)
  3511.                 printf("%s (%s): ", getmonth(n->shortdate),
  3512.                 convtoeurodate(n->shortdate));
  3513.             if (n->requests >= 0)
  3514.                 printgraph(16, n->requests, MONTHMARK, MARK,
  3515.                 largestmonthnum);
  3516.             if (printbytes && n->filesize >= 0) {
  3517.                 printf("        bytes : ");
  3518.                 printgraph(16, n->filesize, MONTHBYTEMARK,
  3519.                 BYTEMARK, largestmonthnum);
  3520.             }
  3521.         }
  3522.         else if (!strcmp(type, "weekly")) {
  3523.             if (n->shortdate != NULL)
  3524.                 printf("Week of %s: ",
  3525.                 convtoeurodate(getshortdate(n->shortdate, 1)));
  3526.             if (n->requests >= 0)
  3527.                 printgraph(18, n->requests, WEEKMARK, MARK,
  3528.                 largestweeknum);
  3529.             if (printbytes && n->filesize >= 0) {
  3530.                 printf("          bytes : ");
  3531.                 printgraph(18, n->filesize, WEEKBYTEMARK,
  3532.                 BYTEMARK, largestweeknum);
  3533.             }
  3534.         }
  3535.         else if (!strcmp(type, "daily")) {
  3536.             if (n->shortdate != NULL)
  3537.                 printf("%s (%s): ",
  3538.                 convtoeurodate(n->shortdate),
  3539.                 days[getweekday(n->shortdate)]);
  3540.             if (n->requests >= 0)
  3541.                 printgraph(16, n->requests, DAYMARK, MARK,
  3542.                 largestdaynum);
  3543.             if (printbytes && n->filesize >= 0) {
  3544.                 printf("        bytes : ");
  3545.                 printgraph(16, n->filesize, DAYBYTEMARK,
  3546.                 BYTEMARK, largestdaynum);
  3547.             }
  3548.         }
  3549.         else if (!strcmp(type, "hourly")) {
  3550.             if (n->shortdate != NULL)
  3551.                 printf("\n%s (%s)\n\n",
  3552.                 convtoeurodate(n->shortdate),
  3553.                 days[getweekday(n->shortdate)]);
  3554.             if (n->hour >= 0)
  3555.                 printhour(n->hour);
  3556.             if (n->requests >= 0)
  3557.                 printgraph(11, n->requests, HOURMARK, MARK,
  3558.                 largesthournum);
  3559.             if (printbytes && n->filesize >= 0) {
  3560.                 printf("   bytes : ");
  3561.                 printgraph(11, n->filesize, HOURBYTEMARK,
  3562.                 BYTEMARK, largesthournum);
  3563.             }
  3564.             if (n->total >= 0)
  3565.                 printf("\n    total: %d\n", n->total);
  3566.         }
  3567.         n = n->next;
  3568.     }
  3569. }
  3570.  
  3571. void printgraph(beforelen, numbers, numspermark, mark, bignum)
  3572.      int beforelen;
  3573.      long int numbers;
  3574.      int numspermark;
  3575.      char mark;
  3576.      long int bignum;
  3577. {
  3578.     int i, tmpnumbers, marknum, truncatelen, graphlen, bignumlen;
  3579.  
  3580.     bignumlen = numlen(bignum);
  3581.     truncatelen = (TRUNCATE < 10) ? 0 : TRUNCATE;
  3582.  
  3583.     tmpnumbers = numbers;
  3584.     for (marknum = 0; tmpnumbers != 0 && tmpnumbers > numspermark;
  3585.     tmpnumbers -= numspermark)
  3586.         marknum++;
  3587.     if (tmpnumbers >= (numspermark / 2))
  3588.         marknum++;
  3589.  
  3590.     graphlen = beforelen + bignumlen + marknum + 5;
  3591.     if (truncatelen && graphlen > TRUNCATE) {
  3592.         marknum = truncatelen - (beforelen + bignumlen + 5);
  3593.         i = bignumlen - numlen(numbers);
  3594.         while (i-- > 0)
  3595.             putchar(' ');
  3596.         printf("%d : ", numbers);
  3597.         while (marknum--) {
  3598.             if (marknum == 3 || marknum == 4)
  3599.                 putchar('|');
  3600.             else
  3601.                 putchar(mark);
  3602.         }
  3603.         putchar('\n');
  3604.     }
  3605.     else {
  3606.         i = bignumlen - numlen(numbers);
  3607.         while (i-- > 0)
  3608.             putchar(' ');
  3609.         printf("%d : ", numbers);
  3610.         while (marknum--)
  3611.             putchar(mark);
  3612.         putchar('\n');
  3613.     }
  3614. }
  3615.  
  3616. void printtree(e, reqfieldlen, bytefieldlen)
  3617.      struct requestentry *e;
  3618.      int reqfieldlen;
  3619.      int bytefieldlen;
  3620. {
  3621.     int i, j, status;
  3622.     long date, filesize, requestnum;
  3623.     char *s, *t, datestr[LONGDATELEN],
  3624.         tempstr[REQUESTLEN], path[REQUESTLEN];
  3625.  
  3626.     if (e != NULL) {
  3627.         printtree(e->right, reqfieldlen, bytefieldlen);
  3628.  
  3629.         j = 0;
  3630.         t = (char *) strdup(e->request);
  3631.  
  3632.         path[0] = '\0';
  3633.         while (1) {
  3634.             s = (char *) strtok((j++) ? NULL : t, "/");
  3635.             if (s == NULL)
  3636.                 break;
  3637.             sprintf(tempstr, "%s/%s", path, s);
  3638.             strcpy(path, tempstr);
  3639.  
  3640.             status = hashlookupreq(path, &date, &filesize,
  3641.             &requestnum);
  3642.  
  3643.             if (!status || strstr(path, "..") || !strcmp(s, "."))
  3644.                 continue;
  3645.             if (checkfiles == 0)
  3646.                 strcpy(tempstr, path);
  3647.             else
  3648.                 sprintf(tempstr, "%s%s", rootdir, path);
  3649.             if (checkfiles)
  3650. #ifdef SHOWTREEFILES
  3651.                 if (!isdirectory(tempstr) && !isfile(tempstr))
  3652. #else
  3653.                 if (!isdirectory(tempstr))
  3654. #endif
  3655.                     continue;
  3656.  
  3657.             hashremreq(path);
  3658.  
  3659.             i = reqfieldlen - numlen(requestnum) - 1;
  3660.             while (i-- > 0)
  3661.                 putchar(' ');
  3662.             printf("%d : ", requestnum);
  3663.  
  3664.             if (date != -1) {
  3665. #ifdef SHOWSECONDS
  3666.                 strcpy(datestr, getdatestr(date, 2));
  3667.                 printf("%s : ", datestr);
  3668. #else
  3669.                 strcpy(datestr, getdatestr(date, 3));
  3670.                 printf("%s : ", datestr);
  3671. #endif
  3672.             }
  3673.             else
  3674. #ifdef SHOWSECONDS
  3675.                 printf("xx/xx/xx xx:xx:xx : ");
  3676. #else
  3677.                 printf("xx/xx/xx : ");
  3678. #endif
  3679.             if (printbytes) {
  3680.                 i = bytefieldlen - numlen(filesize) - 1;
  3681.                 while (i-- > 0)
  3682.                     putchar(' ');
  3683.                 printf("%d : ", filesize);
  3684.             }
  3685.  
  3686.             i = (numstrchr(path, '/') - 1) * 2;
  3687.             while (i-- > 0)
  3688.                 putchar(' ');
  3689.  
  3690.             if (checkfiles) {
  3691.                 if (isfile(tempstr))
  3692.                     printf("%s\n", s);
  3693.                 else if (isdirectory(tempstr))
  3694.                     printf("/%s\n", s);
  3695.             }
  3696.             else
  3697.                 printf("%s\n", s);
  3698.         }
  3699.         free(t);
  3700.         printtree(e->left, reqfieldlen, bytefieldlen);
  3701.     }
  3702. }
  3703.  
  3704. int isdirectory(path)
  3705.      char *path;
  3706. {
  3707.     struct stat stbuf;
  3708.  
  3709.     if (stat(path, &stbuf))
  3710.         return 0;
  3711.     return ((stbuf.st_mode & S_IFMT) == S_IFDIR) ? 1 : 0;
  3712. }
  3713.  
  3714. int isfile(path)
  3715.      char *path;
  3716. {
  3717.     struct stat stbuf;
  3718.  
  3719.     if (stat(path, &stbuf))
  3720.         return 0;
  3721.     return ((stbuf.st_mode & S_IFMT) == S_IFREG) ? 1 : 0;
  3722. }
  3723.  
  3724. void sortrequests(e)
  3725.      struct requestentry *e;
  3726. {
  3727.     if (e != NULL) {
  3728.         sortrequests(e->right);
  3729.         uniquereqnum++;
  3730.         if (e->requestnum > largestreqnum)
  3731.             largestreqnum = e->requestnum;
  3732.         if (e->requestsize > largestbytenum)
  3733.             largestbytenum = e->requestsize;
  3734.         if (e->filesize > largestfilesizenum)
  3735.             largestfilesizenum = e->filesize;
  3736.         sortedrequestlist = (struct requestentry *)
  3737.         addsortrequestentry(sortedrequestlist, e->request,
  3738.         e->date, e->requestnum, e->filesize, e->requestsize);
  3739.         sortrequests(e->left);
  3740.     }
  3741. }
  3742.  
  3743. void printrequests(e, reqfieldlen, bytefieldlen, sizefieldlen)
  3744.      struct requestentry *e;
  3745.      int reqfieldlen;
  3746.      int bytefieldlen;
  3747.      int sizefieldlen;
  3748. {
  3749.     int i, reqlen, truncatelen, datelen;
  3750.     char date[LONGDATELEN];
  3751.     static int j;
  3752.  
  3753. #ifdef SHOWSECONDS
  3754.     datelen = 17;
  3755. #else
  3756.     datelen = 8;
  3757. #endif
  3758.  
  3759.     if (e != NULL) {
  3760.         printrequests(e->right, reqfieldlen, bytefieldlen,
  3761.         sizefieldlen);
  3762.         if (toplines && j++ >= toplines)
  3763.             return;
  3764.         i = reqfieldlen - numlen(e->requestnum) - 1;
  3765.         while (i-- > 0)
  3766.             putchar(' ');
  3767. #ifdef SHOWSECONDS
  3768.         strcpy(date, getdatestr(e->date, 2));
  3769.         printf("%d : %s : ", e->requestnum, date);
  3770. #else
  3771.         strcpy(date, getdatestr(e->date, 3));
  3772.         printf("%d : %s : ", e->requestnum, date);
  3773. #endif
  3774.         truncatelen = (TRUNCATE < 10) ? 0 : TRUNCATE;
  3775.         if (truncatelen) {
  3776.             reqlen = reqfieldlen + ((printbytes) ? (bytefieldlen +
  3777.             sizefieldlen + 6) : 0) + datelen + strlen(e->request) +
  3778.             7;
  3779.             if (reqlen > truncatelen) {
  3780.                 reqlen = truncatelen - reqfieldlen -
  3781.                 ((printbytes) ? (bytefieldlen + sizefieldlen +
  3782.                 6) : 0) - datelen - 7;
  3783.                 (e->request)[reqlen] = '\0';
  3784.             }
  3785.         }
  3786.         if (printbytes) {
  3787.             i = bytefieldlen - numlen(e->requestsize) - 1;
  3788.             while (i-- > 0)
  3789.                 putchar(' ');
  3790.             printf("%d / ", e->requestsize);
  3791.             i = sizefieldlen - numlen(e->filesize) - 1;
  3792.             while (i-- > 0)
  3793.                 putchar(' ');
  3794.             printf("%d : ", e->filesize);
  3795.         }
  3796. #ifdef PRINTURLS
  3797.         if (printhtml)
  3798.             printf("<a href=\"%s%s\">", SERVERSITE,
  3799.             (e->request) + 1);
  3800. #endif
  3801.         printf("%s", e->request);
  3802. #ifdef PRINTURLS
  3803.         if (printhtml)
  3804.             printf("</a>");
  3805. #endif
  3806.         putchar('\n');
  3807.         fflush(stdout);
  3808.         printrequests(e->left, reqfieldlen, bytefieldlen,
  3809.         sizefieldlen);
  3810.     }
  3811. }
  3812.  
  3813. void sortdomains(e)
  3814.      struct domainentry *e;
  3815. {
  3816.     int i, u;
  3817.  
  3818.     if (e != NULL) {
  3819.         sortdomains(e->right);
  3820.         i = numstrchr(e->domain, '.');
  3821.         if (!i || i == 1)
  3822.             uniquedomnum++;
  3823.         if (e->filesize > largestbytenum)
  3824.             largestbytenum = e->filesize;
  3825.         if (e->requestnum > largestdomnum)
  3826.             largestdomnum = e->requestnum;
  3827.         u = hashuniqdn(e->domain);
  3828.         if (u > largestudomnum)
  3829.             largestudomnum = u;
  3830.         sorteddomainlist = (struct domainentry *)
  3831.         addsortdomainentry(sorteddomainlist, e->domain,
  3832.         e->date, e->requestnum, e->filesize, u);
  3833.         sortdomains(e->left);
  3834.     }
  3835. }
  3836.  
  3837. void printdomains(e, domfieldlen, bytefieldlen, uniqfieldlen)
  3838.      struct domainentry *e;
  3839.      int domfieldlen;
  3840.      int bytefieldlen;
  3841.      int uniqfieldlen;
  3842. {
  3843.     int i, j;
  3844.     char date[LONGDATELEN];
  3845.     static int k;
  3846.  
  3847.     if (e != NULL) {
  3848.         printdomains(e->right, domfieldlen, bytefieldlen, uniqfieldlen);
  3849.         if (toplines && k++ >= toplines)
  3850.             return;
  3851.         i = domfieldlen - numlen(e->requestnum) - 1;
  3852.         while (i-- > 0)
  3853.             putchar(' ');
  3854.         printf("%d : ", e->requestnum);
  3855.         i = uniqfieldlen - numlen(e->unique) - 1;
  3856.         while (i-- > 0)
  3857.             putchar(' ');
  3858.         printf("%d : ", e->unique);
  3859.  
  3860. #ifdef SHOWSECONDS
  3861.         strcpy(date, getdatestr(e->date, 2));
  3862.         printf("%s : ", date);
  3863. #else
  3864.         strcpy(date, getdatestr(e->date, 3));
  3865.         printf("%s : ", date);
  3866. #endif
  3867.         if (printbytes) {
  3868.             i = bytefieldlen - numlen(e->filesize) - 1;
  3869.             if (i < 0)
  3870.                 i = 1;
  3871.             while (i-- > 0)
  3872.                 putchar(' ');
  3873.             printf("%d : ", e->filesize);
  3874.         }
  3875.         j = numstrchr(e->domain, '.') - 1;
  3876.         while (j-- > 0)
  3877.             putchar(' ');
  3878.         if (domainfile != NULL && numstrchr(e->domain, '.') == 1 &&
  3879.         hashlookupdom(e->domain) != NULL)
  3880.             printf("%s (%s)\n", hashlookupdom(e->domain),
  3881.             e->domain);
  3882.         else
  3883.             printf("%s\n", e->domain);
  3884.         fflush(stdout);
  3885.         printdomains(e->left, domfieldlen, bytefieldlen, uniqfieldlen);
  3886.     }
  3887. }
  3888.  
  3889. char *lookupnumaddr(numaddress)
  3890.      char *numaddress;
  3891. {
  3892.     char *p;
  3893.     unsigned long addr;
  3894.     struct hostent *he;
  3895.  
  3896.     addr = inet_addr(numaddress);
  3897.     if (addr == -1)
  3898.         return numaddress;
  3899.  
  3900.     p = (char *) hashlookupnumaddr(numaddress);
  3901.     if (p != NULL)
  3902.         return p;
  3903.  
  3904.     he = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
  3905.     if (he) {
  3906.         addhash(he->h_name, numaddress);
  3907.         return he->h_name;
  3908.     }
  3909.     else
  3910.         return numaddress;
  3911. }
  3912.  
  3913. int addrcmp(addr1, addr2)
  3914.      char *addr1;
  3915.      char *addr2;
  3916. {
  3917.     unsigned long num1, num2;
  3918.  
  3919.     num1 = inet_addr(addr1);
  3920.     num2 = inet_addr(addr2);
  3921.  
  3922.     if (num1 > num2)
  3923.         return 1;
  3924.     else if (num1 < num2)
  3925.         return -1;
  3926.  
  3927.     return 0;
  3928. }
  3929.  
  3930. int numlen(num)
  3931.      long int num;
  3932. {
  3933.     int i;
  3934.  
  3935.     i = 0;
  3936.     while (num /= 10)
  3937.         i++;
  3938.  
  3939.     return i;
  3940. }
  3941.  
  3942. char *getlocaltime()
  3943. {
  3944.     static char s[LONGDATELEN], tmp[LONGDATELEN];
  3945.     time_t tp;
  3946.  
  3947.     time(&tp);
  3948. #ifndef VMS
  3949.     strftime(s, LONGDATELEN, "%a %b %d %H:%M:%S %p %Z %Y", localtime(&tp));
  3950. #else
  3951.     strcpy(s, asctime(localtime(&tp)));
  3952. #endif
  3953.  
  3954. #ifdef EURODATE
  3955.     strcpy(tmp, s);
  3956.     tmp[4] = s[8];
  3957.     tmp[5] = s[9];
  3958.     tmp[6] = ' ';
  3959.     tmp[7] = s[4];
  3960.     tmp[8] = s[5];
  3961.     tmp[9] = s[6];
  3962.  
  3963.     return tmp;
  3964. #else
  3965.     return s;
  3966. #endif
  3967. }
  3968.  
  3969. long getthetime()
  3970. {
  3971.     long thetime;
  3972.     time_t tp;
  3973.  
  3974.     thetime = (long) time(&tp);
  3975.     return thetime;
  3976. }
  3977.  
  3978. char *getmonth(shortdate)
  3979.      char *shortdate;
  3980. {
  3981.     int monthnum;
  3982.  
  3983.     monthnum = ((shortdate[0] - '0') * 10) + (shortdate[1] - '0');
  3984.  
  3985.     return months[monthnum - 1];
  3986. }
  3987.  
  3988. int getweekday(shortdate)
  3989.      char *shortdate;
  3990. {
  3991.     int mn, dy, yr, n1, n2;
  3992.  
  3993.     sscanf(shortdate, "%d/%d/%d", &mn, &dy, &yr);
  3994.     yr += CENTURY;
  3995.  
  3996.     if (mn < 3) {
  3997.         mn += 12;
  3998.         yr -= 1;
  3999.     }
  4000.     n1 = (26 * (mn + 1)) / 10;
  4001.     n2 = (int) ((125 * (long) yr) / 100);
  4002.  
  4003.     return ((dy + n1 + n2 - (yr / 100) + (yr / 400) + -1) % 7);
  4004. }
  4005.  
  4006. int getnweekday(mn, dy, yr)
  4007.      int mn;
  4008.      int dy;
  4009.      int yr;
  4010. {
  4011.     int n1, n2;
  4012.  
  4013.     if (mn < 3) {
  4014.         mn += 12;
  4015.         yr -= 1;
  4016.     }
  4017.     n1 = (26 * (mn + 1)) / 10;
  4018.     n2 = (int) ((125 * (long) yr) / 100);
  4019.  
  4020.     return ((dy + n1 + n2 - (yr / 100) + (yr / 400) + -1) % 7);
  4021. }
  4022.  
  4023. long getyearsecs(shortdate)
  4024.      char *shortdate;
  4025. {
  4026.     int i, yearday, yearsecs, prevyeardays;
  4027.     int month, day, year;
  4028.  
  4029.     sscanf(shortdate, "%d/%d/%d", &month, &day, &year);
  4030.     year += CENTURY;
  4031.  
  4032.     for (yearday = i = 0; i < month - 1; i++) {
  4033.         if (i == 1 && IS_LEAP(year))
  4034.             yearday++;
  4035.         yearday += monthdays[i];
  4036.     }
  4037.     yearday += day;
  4038.  
  4039.     prevyeardays = 0;
  4040.     for (i = BASEYEAR; i != year; i++) {
  4041.         if (IS_LEAP(i))
  4042.             prevyeardays++;
  4043.         prevyeardays += DAYSPERYEAR;
  4044.     }
  4045.  
  4046.     yearsecs = (yearday + prevyeardays) * SECSPERDAY;
  4047.  
  4048.     return yearsecs;
  4049. }
  4050.  
  4051. char *getdatestr(yearsecs, type)
  4052.      long int yearsecs;
  4053.      int type;
  4054. {
  4055.     register int day, year, month, hours, minutes;
  4056.     static char date[LONGDATELEN];
  4057.  
  4058.     for (day = 0; yearsecs > SECSPERDAY; day++)
  4059.         yearsecs -= SECSPERDAY;
  4060.  
  4061.     for (year = BASEYEAR; day > DAYSPERYEAR; year++) {
  4062.         if (IS_LEAP(year))
  4063.             day--;
  4064.         day -= DAYSPERYEAR;
  4065.     }
  4066.  
  4067.     if (IS_LEAP(year) && day > (monthdays[0] + monthdays[1])) {
  4068.         day--;
  4069.         yearsecs -= SECSPERDAY;
  4070.     }
  4071.  
  4072.     for (month = 0; day > monthdays[month]; month++)
  4073.         day -= monthdays[month];
  4074.  
  4075.     for (hours = 0; yearsecs > SECSPERHOUR; hours++)
  4076.         yearsecs -= SECSPERHOUR;
  4077.  
  4078.     for (minutes = 0; yearsecs > SECSPERMIN; minutes++)
  4079.         yearsecs -= SECSPERMIN;
  4080.  
  4081. #ifndef EURODATE
  4082.     if (type == 1)
  4083.         sprintf(date, "%s %s %02d %02d:%02d:%02d %d",
  4084.         days[getnweekday(month + 1, day, year)], months[month],
  4085.         day, hours, minutes, yearsecs, year);
  4086.     else if (type == 2)
  4087.         sprintf(date, "%02d/%02d/%02d %02d:%02d:%02d",
  4088.         month + 1, day, year - CENTURY, hours, minutes, yearsecs);
  4089.     else if (type == 3)
  4090.         sprintf(date, "%02d/%02d/%02d",
  4091.         month + 1, day, year - CENTURY);
  4092.     else if (type == 4)
  4093.         sprintf(date, "%s %d, %d", months[month], day, year);
  4094. #else
  4095.     if (type == 1)
  4096.         sprintf(date, "%s %02d %s %02d:%02d:%02d %d",
  4097.         days[getnweekday(month + 1, day, year)], day,
  4098.         months[month], hours, minutes, yearsecs, year);
  4099.     else if (type == 2)
  4100.         sprintf(date, "%02d/%02d/%02d %02d:%02d:%02d",
  4101.         day, month + 1, year - CENTURY, hours, minutes, yearsecs);
  4102.     else if (type == 3)
  4103.         sprintf(date, "%02d/%02d/%02d",
  4104.         day, month + 1, year - CENTURY);
  4105.     else if (type == 4)
  4106.         sprintf(date, "%d %s, %d", day, months[month], year);
  4107. #endif
  4108.  
  4109.     return date;
  4110. }
  4111.  
  4112. int getyearday(shortdate)
  4113.      char *shortdate;
  4114. {
  4115.     int i, month, day, year, yearday;
  4116.     char tmpshortdate[SHORTDATELEN];
  4117.  
  4118.     strcpy(tmpshortdate, shortdate); 
  4119.     sscanf(tmpshortdate, "%d/%d/%d", &month, &day, &year);
  4120.     year += CENTURY;
  4121.     for (yearday = i = 0; i < month - 1; i++) {
  4122.         if (i == 1 && IS_LEAP(year))
  4123.             yearday++;
  4124.         yearday += monthdays[i];
  4125.     }
  4126.     yearday += day;
  4127.  
  4128.     return yearday;
  4129. }
  4130.  
  4131. int getmondaynum(shortdate)
  4132.      char *shortdate;
  4133. {
  4134.     int month, day, year, yearday, weekday, mondayday;
  4135.  
  4136.     sscanf(shortdate, "%d/%d/%d", &month, &day, &year);
  4137.     year += CENTURY;
  4138.  
  4139.     yearday = getyearday(shortdate);
  4140.     weekday = getweekday(shortdate);
  4141.  
  4142.     if (!weekday)
  4143.         weekday = 7;
  4144.     mondayday = yearday - (weekday - 1);
  4145.     if (mondayday <= 0) {
  4146.         mondayday += (DAYSPERYEAR - 1);
  4147.         year--;
  4148.         if (IS_LEAP(year))
  4149.             mondayday++;
  4150.     }
  4151.  
  4152.     return mondayday;
  4153. }
  4154.  
  4155. char *getshortdate(shortdate, getmon)
  4156.      char *shortdate;
  4157.      int getmon;
  4158. {
  4159.     int i, month, day, year, yearday, weekday, sundayday, mondayday;
  4160.     static char newshortdate[SHORTDATELEN];
  4161.  
  4162.     sscanf(shortdate, "%d/%d/%d", &month, &day, &year);
  4163.     year += CENTURY;
  4164.  
  4165.     yearday = getyearday(shortdate);
  4166.     weekday = getweekday(shortdate);
  4167.  
  4168.     if (!weekday)
  4169.         weekday = 7;
  4170.  
  4171.     mondayday = yearday - (weekday - 1);
  4172.     sundayday = yearday + (DAYSPERWEEK - weekday);
  4173.  
  4174.     if (!getmon && sundayday > DAYSPERYEAR) {
  4175.         month++;
  4176.         if (month == 13)
  4177.             month = 1;
  4178.         sundayday -= DAYSPERYEAR;
  4179.         year++;
  4180.     }
  4181.  
  4182.     if (getmon && mondayday <= 0) {
  4183.         month--;
  4184.         if (!month)
  4185.             month = 12;
  4186.         mondayday += (DAYSPERYEAR - 1);
  4187.         year--;
  4188.         if (IS_LEAP(year))
  4189.             mondayday++;
  4190.     }
  4191.  
  4192.     yearday = (getmon) ? mondayday : sundayday;
  4193.  
  4194.     for (i = 0; i < month - 1; i++)
  4195.         if (yearday > monthdays[i])
  4196.             yearday -= monthdays[i];
  4197.         else {
  4198.             if (i == 2 && IS_LEAP(year))
  4199.                 yearday--;
  4200.             break;
  4201.         }
  4202.  
  4203.     sprintf(newshortdate, "%02d/%02d/%02d", i + 1, yearday, year - CENTURY);
  4204.  
  4205.     return newshortdate;
  4206. }
  4207.  
  4208. int daydifference(firstshortdate, secondshortdate)
  4209.      char *firstshortdate;
  4210.      char *secondshortdate;
  4211. {
  4212.     return (int) (getyearsecs(secondshortdate) -
  4213.     getyearsecs(firstshortdate)) / SECSPERDAY;
  4214. }
  4215.  
  4216. int isinlastweek(shortdate, newshortdate)
  4217.      char *shortdate;
  4218.      char *newshortdate;
  4219. {
  4220.     long newsecs, oldsecs;
  4221.  
  4222.     newsecs = getyearsecs(newshortdate);
  4223.     oldsecs = getyearsecs(shortdate);
  4224.  
  4225.     if ((newsecs - oldsecs) <= SECSPERWEEK)
  4226.         return 1;
  4227.     else
  4228.         return 0;
  4229. }
  4230.  
  4231. int isvalidreq(request)
  4232.      char *request;
  4233. {
  4234.     return (strstr(request, "GET") || strstr(request, "HEAD") ||
  4235.     strstr(request, "POST"));
  4236. }
  4237.  
  4238. int ishtmlrequest(request)
  4239.      char *request;
  4240. {
  4241.     return (strstr(request, ".html") || strstr(request, "GET") ||
  4242.     strstr(request, "HEAD"));
  4243. }
  4244.  
  4245. int isscriptrequest(request)
  4246.      char *request;
  4247. {
  4248.     return (strstr(request, "cgi-bin") || strstr(request, "htbin") ||
  4249.     strstr(request, "POST"));
  4250. }
  4251.  
  4252. char *headerend(request)
  4253.      char *request;
  4254. {
  4255.     char *c;
  4256.  
  4257.     if ((c = (char *) strstr(request, "GET")) != NULL)
  4258.         return (c + 3);
  4259.     else if ((c = (char *) strstr(request, "HEAD")) != NULL)
  4260.         return (c + 4);
  4261.     else if ((c = (char *) strstr(request, "POST")) != NULL)
  4262.         return (c + 4);
  4263.  
  4264.     return NULL;
  4265. }
  4266.  
  4267. int isokstring(string, mask, skip)
  4268.      char *string;
  4269.      char *mask;
  4270.      int skip;
  4271. {
  4272.     int i;
  4273.     char *s, *t;
  4274.  
  4275.     if (!strcmp(mask, "NONE"))
  4276.         return 1;
  4277.  
  4278.     i = 0;
  4279.     t = (char *) strdup(mask);
  4280.  
  4281.     if (skip) {
  4282.         while (1) {
  4283.             s = (char *) strtok((i++) ? NULL : t, ",");
  4284.             if (s == NULL)
  4285.                 break;
  4286.             if (isinname(string, s))
  4287.                 return 0;
  4288.         }
  4289.         return 1;
  4290.     }
  4291.     else {
  4292.         while (1) {
  4293.             s = (char *) strtok((i++) ? NULL : t, ",");
  4294.             if (s == NULL)
  4295.                 break;
  4296.             if (isinname(string, s))
  4297.                 return 1;
  4298.         }
  4299.         return 0;
  4300.     }
  4301. }
  4302.  
  4303. int isinname(string, mask)
  4304.      char *string;
  4305.      char *mask;
  4306. {
  4307.     int i, j;
  4308.     char firstchar, lastchar, *tempmask;
  4309.  
  4310.     if (!strcmp(mask, "*"))
  4311.         return 1;
  4312.  
  4313.     firstchar = mask[0];
  4314.     lastchar = mask[(strlen(mask) - 1)];
  4315.     tempmask = (char *) emalloc(strlen(mask));
  4316.  
  4317.     for (i = j = 0; mask[i]; i++)
  4318.         if (mask[i] != '*')
  4319.             tempmask[j++] = mask[i];
  4320.     tempmask[j] = '\0';
  4321.  
  4322.     if (firstchar == '*') {
  4323.         if (lastchar == '*') {
  4324.             if ((char *) strstr(string, tempmask))
  4325.                 return 1;
  4326.         }
  4327.         else {
  4328.             if ((char *) strstr(string, tempmask) ==
  4329.             string + strlen(string) - strlen(tempmask))
  4330.                 return 1;
  4331.         }
  4332.     }
  4333.     else if (lastchar == '*') {
  4334.         if ((char *) strstr(string, tempmask) == string)
  4335.             return 1;
  4336.     }
  4337.     else {
  4338.         if (!strcmp(string, tempmask))
  4339.             return 1;
  4340.     }
  4341.  
  4342.     return 0;
  4343. }
  4344.  
  4345. int isokdate(monthstr, daystr, yearstr, shortdate)
  4346.      char *monthstr;
  4347.      char *daystr;
  4348.      char *yearstr;
  4349.      char *shortdate;
  4350. {
  4351.     int month, day, year, uppernum, lowernum;
  4352.  
  4353.     sscanf(shortdate, "%d/%d/%d", &month, &day, &year);
  4354.  
  4355.     if (isnumber(monthstr))
  4356.         if (atoi(monthstr) != month)
  4357.             return 0;
  4358.     if (isnumber(daystr))
  4359.         if (atoi(daystr) != day)
  4360.             return 0;
  4361.     if (isnumber(yearstr)) {
  4362.         if (atoi(yearstr) > CENTURY)
  4363.             year += CENTURY;
  4364.         if (atoi(yearstr) != year)
  4365.             return 0;
  4366.     }
  4367.  
  4368.     if (strchr(monthstr, '-')) {
  4369.         parsedaterange(monthstr, &lowernum, &uppernum);
  4370.         if (month < lowernum || month > uppernum)
  4371.             return 0;
  4372.     }
  4373.     if (strchr(daystr, '-')) {
  4374.         parsedaterange(daystr, &lowernum, &uppernum);
  4375.         if (day < lowernum || day > uppernum)
  4376.             return 0;
  4377.     }
  4378.     if (strchr(yearstr, '-')) {
  4379.         parsedaterange(yearstr, &lowernum, &uppernum);
  4380.         if (year < lowernum || year > uppernum)
  4381.             return 0;
  4382.     }
  4383.  
  4384.     return 1;
  4385. }
  4386.  
  4387. int isokhour(date, lowhour, highhour)
  4388.      char *date;
  4389.      int lowhour;
  4390.      int highhour;
  4391. {
  4392.     int hour;
  4393.     char hourstr[3];
  4394.  
  4395.     sprintf(hourstr, "%c%c", (date[11] == ' ') ? '0' : date[11], date[12]);
  4396.     hour = atoi(hourstr);
  4397.  
  4398.     if (hour >= lowhour && hour <= highhour)
  4399.         return 1;
  4400.     return 0;
  4401. }
  4402.  
  4403. void parsedaymask(mask, lowday, highday)
  4404.      char *mask;
  4405.      int *lowday;
  4406.      int *highday;
  4407. {
  4408.     int i, j;
  4409.     char templowday[4], temphighday[4];
  4410.  
  4411.     if (!strchr(mask, '-')) {
  4412.         if (!strcmp(mask, "weekdays")) {
  4413.             *lowday = 1;
  4414.             *highday = 5;
  4415.         }
  4416.         else if (!strcmp(mask, "weekends")) {
  4417.             *lowday = 6;
  4418.             *highday = 7;
  4419.         }
  4420.         else {
  4421.             *lowday = getday(mask);
  4422.             *highday = getday(mask);
  4423.         }
  4424.     }
  4425.     else {
  4426.         for (i = 0, j = 0; mask[i] && mask[i] != '-'; i++)
  4427.             templowday[j++] = mask[i];
  4428.         templowday[j] = '\0';
  4429.  
  4430.         for (i++, j = 0; mask[i]; i++)
  4431.             temphighday[j++] = mask[i];
  4432.         temphighday[j] = '\0';
  4433.  
  4434.         if (temphighday[0] != '\0')
  4435.             *highday = getday(temphighday);
  4436.         else
  4437.             *highday = 7;
  4438.  
  4439.         if (templowday[0] != '\0')
  4440.             *lowday = getday(templowday);
  4441.         else
  4442.             *lowday = 1;
  4443.     }
  4444. }
  4445.  
  4446. int getday(string)
  4447.      char *string;
  4448. {
  4449.     int i;
  4450.     char *tempstr, *tempday;
  4451.  
  4452.     tempstr = (char *) strdup(string);
  4453.     makelower(string);
  4454.  
  4455.     tempday = (char *) emalloc(4);
  4456.     for (i = 0; days[i]; i++) {
  4457.         strcpy(tempday, days[i]);
  4458.         makelower(tempday);
  4459.         if (strstr(tempstr, tempday))
  4460.             break;
  4461.     }
  4462.  
  4463.     return ((!i) ? 7 : i);
  4464. }
  4465.  
  4466. int isokday(date, lowday, highday)
  4467.      char *date;
  4468.      int lowday;
  4469.      int highday;
  4470. {
  4471.     int i, dateday;
  4472.  
  4473.     for (i = 0; !strstr(date, days[i]); i++)
  4474.         ;
  4475.     dateday = (!i) ? 7 : i;
  4476.  
  4477.     if (dateday >= lowday && dateday <= highday)
  4478.         return 1;
  4479.     return 0;
  4480. }
  4481.  
  4482. void parsedatemask(datemask, monthstr, daystr, yearstr)
  4483.      char *datemask;
  4484.      char *monthstr;
  4485.      char *daystr;
  4486.      char *yearstr;
  4487. {
  4488.     int i, j;
  4489.  
  4490.     for (i = 0; isokdatechar(datemask[i]); i++)
  4491.         monthstr[i] = datemask[i];
  4492.     monthstr[i++] = '\0';
  4493.     for (j = 0; isokdatechar(datemask[i]); i++)
  4494.         daystr[j++] = datemask[i];
  4495.     daystr[j] = '\0';
  4496.     i++;
  4497.     for (j = 0; isokdatechar(datemask[i]); i++)
  4498.         yearstr[j++] = datemask[i];
  4499.     yearstr[j] = '\0';
  4500. }
  4501.  
  4502. void parsehourmask(hourmask, lowhour, highhour)
  4503.      char *hourmask;
  4504.      int *lowhour;
  4505.      int *highhour;
  4506. {
  4507.     int i, j;
  4508.  
  4509.     if (!strchr(hourmask, '-')) {
  4510.         *lowhour = atoi(hourmask);
  4511.         *highhour = atoi(hourmask);
  4512.     }
  4513.     else {
  4514.         for (i = j = 0; hourmask[i] != '-'; i++)
  4515.             if (isdigit(hourmask[i]))
  4516.                 j = (j * 10) + (hourmask[i] - '0');
  4517.         *lowhour = (j) ? j : 0;
  4518.  
  4519.         for (i++, j = 0; hourmask[i]; i++)
  4520.             if (isdigit(hourmask[i]))
  4521.                 j = (j * 10) + (hourmask[i] - '0');
  4522.         *highhour = (j) ? j : 23;
  4523.     }
  4524. }
  4525.  
  4526. int isokdatechar(c)
  4527.      char c;
  4528. {
  4529.     if (c == '*' || isdigit(c) || c == '[' || c == ']' || c == '-')
  4530.         return 1;
  4531.     return 0;
  4532. }
  4533.  
  4534. void parsedaterange(datemask, lower, upper)
  4535.      char *datemask;
  4536.      int *lower;
  4537.      int *upper;
  4538. {
  4539.     int lowernum, uppernum;
  4540.  
  4541.     lowernum = uppernum = 0;
  4542.     while (*datemask != '-') {
  4543.         if (isdigit(*datemask))
  4544.             lowernum = (lowernum * 10) + (*datemask - '0');
  4545.         datemask++;
  4546.     }
  4547.     datemask++;
  4548.     while (*datemask) {
  4549.         if (isdigit(*datemask))
  4550.             uppernum = (uppernum * 10) + (*datemask - '0');
  4551.         datemask++;
  4552.     }
  4553.  
  4554.     *lower = lowernum;
  4555.     *upper = uppernum;
  4556. }
  4557.  
  4558. int isnumber(s)
  4559.      char *s;
  4560. {
  4561.     while (*s) {
  4562.         if (!isdigit(*s))
  4563.             return 0;
  4564.         s++;
  4565.     }
  4566.  
  4567.     return 1;
  4568. }
  4569.  
  4570. int numstrchr(s, c)
  4571.      char *s;
  4572.      char c;
  4573. {
  4574.     int i;
  4575.  
  4576.     for (i = 0; *s != '\0'; s++)
  4577.         if (*s == c)
  4578.             i++;
  4579.     return i;
  4580. }
  4581.  
  4582. int isip(address)
  4583.      char *address;
  4584. {
  4585.     int dots, prevdot;
  4586.  
  4587.     dots = 0;
  4588.     prevdot = 1;
  4589.     while (*address != (char) NULL) {
  4590.         if (*address == '.') {
  4591.             dots++;
  4592.             if (prevdot)
  4593.                 return 0;
  4594.             prevdot = 1;
  4595.         }
  4596.         else {
  4597.             if (*address < '0' || *address > '9')
  4598.                 return 0;
  4599.             prevdot = 0;
  4600.         }
  4601.         address++;
  4602.     }
  4603.     return (dots == 3) && !prevdot;
  4604. }
  4605.  
  4606. long getsize(request)
  4607.      char *request;
  4608. {
  4609.     char path[REQUESTLEN];
  4610.     long size;
  4611.     struct stat stbuf;
  4612.  
  4613.     size = hashlookupsize(request);
  4614.  
  4615.     if (size == -1) {
  4616.         sprintf(path, "%s%s", rootdir, request);
  4617.         if (stat(path, &stbuf)) {
  4618.             addhashsize(0, request);
  4619.             return 0;
  4620.         }
  4621.         else {
  4622.             addhashsize(stbuf.st_size, request);
  4623.             return stbuf.st_size;
  4624.         }
  4625.     }
  4626.     else
  4627.         return size;
  4628. }
  4629.  
  4630. long isempty(file)
  4631.      char *file;
  4632. {
  4633.     struct stat stbuf;
  4634.  
  4635.     if (stat(file, &stbuf))
  4636.         return 1;
  4637.  
  4638.     return (!(stbuf.st_size));
  4639. }
  4640.  
  4641. void makelower(string)
  4642.      char *string;
  4643. {
  4644.     int i, j;
  4645.     char *tempstr;
  4646.  
  4647.     tempstr = (char *) strdup(string);
  4648.     for (i = j = 0; string[j] && tempstr[i]; i++)
  4649.         string[j++] = tolower(tempstr[i]);
  4650.     string[j] = '\0';
  4651.     free(tempstr);
  4652. }
  4653.  
  4654. void removespaces(string)
  4655.      char *string;
  4656. {
  4657.     int i, j;
  4658.     char *tempstr;
  4659.  
  4660.     tempstr = (char *) strdup(string);
  4661.     for (i = j = 0; tempstr[i]; i++) {
  4662.         if (isspace(tempstr[i]))
  4663.             continue;
  4664.         else
  4665.             string[j++] = tempstr[i];
  4666.     }
  4667.     string[j] = '\0';
  4668. }
  4669.  
  4670. void fixslash(string)
  4671.      char *string;
  4672. {
  4673.         char *c;
  4674.  
  4675.     c = (char *) string + strlen(string) - 1;
  4676.     while (*c == '/' || isspace(*c)) {
  4677.         *c = '\0';
  4678.         c--;
  4679.     }
  4680. }
  4681.  
  4682. char *strdup(s)
  4683.      char *s;
  4684. {
  4685.     char *p;
  4686.  
  4687.     p = (char *) emalloc(strlen(s) + 1);
  4688.     strcpy(p, s);
  4689.     return p;
  4690. }
  4691.  
  4692. void setupprogress(logfile)
  4693.      char *logfile;
  4694. {
  4695.     int i;
  4696.     char logline[MAXLINE];
  4697.     FILE *fp;
  4698.  
  4699.     fprintf(stderr, "Log file length...");
  4700.  
  4701.     fp = fopen(logfile, "r");
  4702.     while (fgets(logline, MAXLINE, fp) != NULL)
  4703.         loglines++;
  4704.     fclose(fp);
  4705.  
  4706.     linespermark = loglines / PROGRESSLEN;
  4707.     if (!linespermark)
  4708.         linespermark = 1;
  4709.  
  4710.     fprintf(stderr, " %d lines. ~%d line%s per mark.\n",
  4711.     loglines, linespermark, (linespermark == 1) ? "" : "s");
  4712.  
  4713.     for (i = 0; i != PROGRESSLEN; i++) {
  4714.         if (!i)
  4715.             fputc('0', stderr);
  4716.         else if (i == (PROGRESSLEN / 2))
  4717.             fprintf(stderr, "50");
  4718.         else if (i == (PROGRESSLEN - 3))
  4719.             fprintf(stderr, "100");
  4720.         else
  4721.             fputc(' ', stderr);
  4722.     }
  4723.     fputc('\n', stderr);
  4724.     for (i = 0; i != PROGRESSLEN; i++) {
  4725.         if (!i)
  4726.             fputc('|', stderr);
  4727.         else if (i == (PROGRESSLEN / 2))
  4728.             fputc('|', stderr);
  4729.         else
  4730.             fputc('-', stderr);
  4731.     }
  4732.     fprintf(stderr, "|\n");
  4733. }
  4734.  
  4735. void updateprogress(line)
  4736.      int line;
  4737. {
  4738.     if (!(line % linespermark)) {
  4739.         fputc('*', stderr);
  4740.         fflush(stderr);
  4741.     }
  4742. }
  4743.  
  4744. void *emalloc(i)
  4745.      int i;
  4746. {
  4747.     void *p;
  4748.  
  4749.     if ((p = (void *) malloc(i)) == NULL)
  4750.         progerr("Ran out of memory!");
  4751.     return p;
  4752. }
  4753.  
  4754. void noactivity()
  4755. {
  4756.     if (printhtml) {
  4757.         printf("<p>\n<b>No activity reported on this date.</b>\n");
  4758.         printf("<p>\n<hr>\n");
  4759.         printbottomhtml();
  4760.     }
  4761.     else
  4762.         printf("\nNo activity reported on this date.\n");
  4763. #ifdef VMS
  4764.     exit(1);
  4765. #else
  4766.     exit(0);
  4767. #endif
  4768. }
  4769.  
  4770. void printbottomhtml()
  4771. {
  4772.     printf("<i>These statistics were produced by <a href=\"");
  4773.     printf("%s\">%s %s</a>.</i>\n</body>\n", DOCURL, PROGNAME, VERSION);
  4774. }
  4775.  
  4776. void progerr(errorstr)
  4777.      char *errorstr;
  4778. {
  4779. #ifdef CGI
  4780.     printf("Content-type: text/html\n\n");
  4781.     printf("<title>Getstats error</title>\n");
  4782.     printf("<h1>Getstats error</h1>\n<p>\n");
  4783.     printf("<code>%s: %s</code>\n", PROGNAME, errorstr);
  4784. #ifdef VMS
  4785.     exit(1);
  4786. #else
  4787.     exit(0);
  4788. #endif
  4789. #else
  4790.     fprintf(stderr, "%s: %s\n", PROGNAME, errorstr);
  4791.     exit(-1);
  4792. #endif
  4793. }
  4794.  
  4795. void usage()
  4796. {
  4797.     printf("  usage: %s [-C,-N,-P,-G,-A,-O], -M, ", PROGNAME);
  4798.     printf("-c, -m, -w, -ds -d, -hs, -h,\n");
  4799.     printf("         -e [\"file\"], -a, ");
  4800.     printf("-dt, [-f,-fa,-fd,-fb], [-r,-ra,-rd,-rb,-rf],\n");
  4801.     printf("         [-dn,-da,-dd,-db,-du], -dl #, -df \"file\",\n");
  4802.     printf("         -sa \"string\", -ss \"string\", ");
  4803.     printf("-sr \"string\", -sp \"string\",\n");
  4804.     printf("         -sd \"string\", -sh \"string\", -sw \"string\",\n");
  4805.     printf("         -b, -i, -ip, -p, -ht, -t #, -dr [\"dir\"], ");
  4806.     printf("-l \"file\"\n");
  4807.     printf("options: No option gives the default report.\n");
  4808.     printf("         -C, -N, -P, -G, -A, -O\n");
  4809.     printf("             : use CERN, NCSA, Plexus, GN, MacHTTP,\n");
  4810.     printf("               or UNIX Gopher server log format\n");
  4811.     printf("         -M  : use common logfile format\n");
  4812.     printf("         -c, -m, -w, -ds, -d, -hs, -h, -e, -a\n");
  4813.     printf("             : concise, monthly, weekly, daily summary, ");
  4814.     printf("daily, hourly summary,\n");
  4815.     printf("               hourly, error, and all reports\n");
  4816.     printf("         -f, -fa, -fd, -fb : full report\n");
  4817.     printf("             : sorted by address, accesses, date, or bytes\n");
  4818.     printf("         -r, -ra, -rd, -rb, -rf : file request report\n");
  4819.     printf("             : sorted by request, accesses, date, bytes, ");
  4820.     printf("or file size\n");
  4821.     printf("         -dn, -da, -dd, -db, -du : domain report\n");
  4822.     printf("             : sorted by domain, accesses, date, bytes, ");
  4823.     printf("or unique domains\n");
  4824.     printf("         -dl : number of domain levels to report\n");
  4825.     printf("         -df : file to look up domain codes from\n");
  4826.     printf("         -dt : directory tree report\n");
  4827.     printf("         -sa, -ss, -sr, -sp : filter log by ");
  4828.     printf("\"string\"\n");
  4829.     printf("             : only addresses, skip addresses, only reqs, ");
  4830.     printf("skip reqs\n");
  4831.     printf("         -sd : report entries with date \"m/d/y\"\n");
  4832.     printf("         -sh : report entries with hour \"h\"\n");
  4833.     printf("         -sw : report entries with day \"day\"\n");
  4834.     printf("         -b  : add byte traffic statistics to all reports\n");
  4835.     printf("         -i  : take input from standard input\n");
  4836.     printf("         -ip : look up all IP addresses\n");
  4837.     printf("         -p  : display progress meter\n");
  4838.     printf("         -ht : produce HTML output\n");
  4839.     printf("         -t  : take top # lines of list reports\n");
  4840.     printf("         -dr : root Web/Gopher directory\n");
  4841.     printf("         -l  : logfile to use\n");
  4842.     printf("   docs: %s\n", DOCURL);
  4843.     exit(-1);
  4844. }
  4845.  
  4846. /*
  4847. ** Version history
  4848. **
  4849. ** 1.0 : Original hack, "getsites", written 6/93 at Honolulu Community College.
  4850. ** 1.1 : Better formatting, checks for malloc() errors.
  4851. ** 1.2 : Fixed a timing error - reports last weeks's numbers/lifetime better.
  4852. ** 1.3 : Complete rewrite. More stable, IP lookup more verbose, netmask and
  4853. **       log file command-line options. Printing slightly prettier.
  4854. ** 1.4 : Now works with NCSA, Plexus, and GN log files! Other small fixes,
  4855. **       rearrangement of time functions, deletion of buggy strptime().
  4856. **       Now can use previous output to lookup hosts.
  4857. ** 1.5 : Fixed Plexus parsing bug, host table lookup fix, added date coverage.
  4858. ** 1.6 : Host lookup faster, no more SYSV-specific time functions,
  4859. **       h_errno now declared, hanging problems possibly fixed.
  4860. ** 1.7 : VMS compatible, fixed CERN date stomping, reports day in dailies,
  4861. **       added second netmask, MAXLINE bigger for GN, improved week code,
  4862. **       removed "offsite", better program flow, file request reporting,
  4863. **       date masking, requests/hour (not officialy released).
  4864. **
  4865. ** Getsites 2.0 becomes Getstats 1.0!
  4866. **
  4867. ** 1.0 : Full report name sort, name filtering, optional lookup,
  4868. **       more date options, domain reporting, fixed all analyze code,
  4869. **       hour reports and filtering, errors and logging, report combos,
  4870. **       request masks, mask lists, day mask, all flag, seconds reporting,
  4871. **       byte reporting, pretty graphs, removed IP field, domain lookup,
  4872. **       summaries, alias paths, gopher, purify'd.
  4873. ** 1.1 : Added CGI, GMTOFFSET, LOGTZ switches, no using -i with VMS,
  4874. **       fixed NCSA tab log, no dirent code, added unique domains, fixed
  4875. **       toplines, convtoyearsecs, "-ip", Gopher root, added "-dr",
  4876. **       ifndefs, static fixes, GN "Sent" and "HTTP", DEC UCX, common format.
  4877. ** 1.2 : REPORTTYPELEN increased, NCSA null addresses, added HEAD and POST,
  4878. **       reports GN2 logs and MacHTTP, empty logs, graphs round up, EURODATE,
  4879. **       no activity fix, monthly report.
  4880. ** Todo: The ability to add HTML to a statistics directory...
  4881. **       Gnuplot (X, Y) output? Report strings? Custom sort report?
  4882. **       Monthly stats? Arbitrary-sized numbers...
  4883. **       Option to display sizes in b, Kb, MB, or GB...
  4884. **       Build on previous stats? External configuration file?
  4885. **
  4886. ** This code is freely distributable but cannot be sold by itself or in 
  4887. ** conjunction with other items without express permission of the author.
  4888. */
  4889.