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

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