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

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