index.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:38k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/index.c 2.63 1999/09/06 18:54:11 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5.
  4.   Generate an index of the web pages that are cached in the system.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1997,98,99 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #include <utime.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <dirent.h>
  20. #include <fcntl.h>
  21. #include <unistd.h>
  22. #include "wwwoffle.h"
  23. #include "misc.h"
  24. #include "proto.h"
  25. #include "config.h"
  26. #include "errors.h"
  27. /*+ A type to contain the information required to sort the files. +*/
  28. typedef struct _FileIndex
  29. {
  30.  URL *url;                      /*+ The URL of the file. +*/
  31.  char *name;                    /*+ The name of the URL. +*/
  32.  char *host;                    /*+ The host of the URL. +*/
  33.  char *type;                    /*+ The type (file extension) of the URL. +*/
  34.  long time;                     /*+ The time of the file (access or modification as appropriate). +*/
  35. }
  36. FileIndex;
  37. /*+ The method of sorting used. +*/
  38. static char *sorttype[]={"none"  ,
  39.                          "mtime" ,
  40.                          "atime" ,
  41.                          "dated" ,
  42.                          "alpha" ,
  43.                          "domain",
  44.                          "type"  ,
  45.                          "none"  };
  46. /*+ An enumerated type for the sort modes. +*/
  47. typedef enum _SortMode
  48. {
  49.  None,                          /*+ No sorting, natural order. +*/
  50.  MTime,                         /*+ Sort by modification time +*/
  51.  ATime,                         /*+ Sort by access time. +*/
  52.  Dated,                         /*+ Sort by modification time with separators. +*/
  53.  Alpha,                         /*+ Sort Alphabetically. +*/
  54.  Domain,                        /*+ Sort by domain name. +*/
  55.  Type,                          /*+ Sort by type (file extension). +*/
  56.  NSortModes                     /*+ The number of sort modes. +*/
  57. }
  58. SortMode;
  59. /*+ The list of files. +*/
  60. static FileIndex **files=NULL;
  61. static int nfiles=0;
  62. /*+ The earliest time that files can appear in the dated list. +*/
  63. static time_t earliest=0;
  64. /*+ The current time. +*/
  65. static time_t now;
  66. static void IndexRoot(int fd);
  67. static void IndexProtocol(int fd,char *proto,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  68. static void IndexHost(int fd,char *proto,char *host,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  69. static void IndexOutgoing(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  70. static void IndexMonitor(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  71. static void IndexLastTime(int fd,char *name,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  72. static void IndexLatest(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt);
  73. static void add_dir(char *name,SortMode mode);
  74. static void add_file(char *name,SortMode mode);
  75. static void dated_separator(int fd,int file,int *lastdays,int *lasthours);
  76. static int sort_alpha(FileIndex **a,FileIndex **b);
  77. static int sort_type(FileIndex **a,FileIndex **b);
  78. static int sort_domain(FileIndex **a,FileIndex **b);
  79. static int sort_time(FileIndex **a,FileIndex **b);
  80. /*++++++++++++++++++++++++++++++++++++++
  81.   Generate an index of the pages that are in the cache.
  82.   int fd The file descriptor to write the output to.
  83.   URL *Url The URL that specifies the path to generate the index for.
  84.   ++++++++++++++++++++++++++++++++++++++*/
  85. void IndexPage(int fd,URL *Url)
  86. {
  87.  char *newpath;
  88.  char *proto=NULL,*host="";
  89.  SortMode sort=NSortModes,s;
  90.  Protocol *protocol=NULL;
  91.  int outgoing=0,monitor=0,lasttime=0,prevtime=0,latest=0,main=0;
  92.  int delopt=0,refopt=0,monopt=0,allopt=0;
  93.  int i;
  94.  if(!strcmp(Url->path,"/index/url/"))
  95.    {
  96.     URL *indexUrl;
  97.     if(Url->args && (indexUrl=SplitURL(Url->args)))
  98.       {
  99.        char *localhost=GetLocalHost(1);
  100.        char *relocate=(char*)malloc(strlen(localhost)+strlen(indexUrl->proto)+strlen(indexUrl->host)+32);
  101.        sprintf(relocate,"http://%s/index/%s/%s?sort=%srn",localhost,indexUrl->proto,indexUrl->host,sorttype[Alpha]);
  102.        HTMLMessage(fd,301,"WWWOFFLE Index URL Redirect",relocate,"IndexURLRedirect",
  103.                    "url",Url->args,
  104.                    "link",relocate+7+strlen(localhost),
  105.                    NULL);
  106.        FreeURL(indexUrl);
  107.        free(localhost);
  108.        free(relocate);
  109.       }
  110.     else
  111.        HTMLMessage(fd,404,"WWWOFFLE Illegal Index Page",NULL,"IndexIllegal",
  112.                    "url",Url->pathp,
  113.                    NULL);
  114.     return;
  115.    }
  116.  newpath=(char*)malloc(strlen(Url->path)-6);
  117.  strcpy(newpath,Url->path+7);
  118.  if(*newpath && newpath[strlen(newpath)-1]=='/')
  119.     newpath[strlen(newpath)-1]=0;
  120.  for(i=0;newpath[i];i++)
  121.     if(newpath[i]=='/')
  122.       {
  123.        newpath[i]=0;
  124.        host=newpath+i+1;
  125.        break;
  126.       }
  127.  proto=newpath;
  128.  for(i=0;i<NProtocols;i++)
  129.     if(!strcmp(proto,Protocols[i].name))
  130.        protocol=&Protocols[i];
  131.  outgoing=!strcmp(proto,"outgoing");
  132.  monitor =!strcmp(proto,"monitor");
  133.  lasttime=!strcmp(proto,"lasttime");
  134.  prevtime=!strncmp(proto,"prevtime",8) && atoi(proto+8)>=0 && atoi(proto+8)<=NUM_PREVTIME_DIR;
  135.  latest  =!strcmp(proto,"latest");
  136.  main=(!protocol && !outgoing && !monitor && !lasttime && !prevtime && !latest);
  137.  if(Url->args)
  138.    {
  139.     char *p=Url->args,*amp;
  140.     do
  141.       {
  142.        amp=strchr(p,'&');
  143.        if(amp)
  144.           *amp=0;
  145.        if(!strncmp(p,"sort=",5))
  146.           for(s=0;s<NSortModes;s++)
  147.              if(!strcmp(p+5,sorttype[s]))
  148.                {sort=s;break;}
  149.        if(!strcmp(p,"delete"))
  150.           delopt=1;
  151.        if(!strcmp(p,"refresh"))
  152.           refopt=1;
  153.        if(!strcmp(p,"monitor"))
  154.           monopt=1;
  155.        if(!strcmp(p,"all"))
  156.           allopt=1;
  157.        if(amp)
  158.          {p=amp+1;*amp='&';}
  159.       }
  160.     while(amp);
  161.    }
  162.  files=NULL;
  163.  nfiles=0;
  164.  now=time(NULL);
  165.  earliest=0;
  166.  if((*host && (strchr(host,'/') || !strcmp(host,"..") || !strcmp(host,"."))) ||
  167.     (main && Url->path[7]) ||
  168.     ((outgoing || monitor || lasttime || prevtime || latest) && *host))
  169.     HTMLMessage(fd,404,"WWWOFFLE Illegal Index Page",NULL,"IndexIllegal",
  170.                 "url",Url->pathp,
  171.                 NULL);
  172.  else if(sort==NSortModes && (outgoing || monitor || lasttime || prevtime || protocol))
  173.    {
  174.     char *localhost=GetLocalHost(1);
  175.     char *relocate=(char*)malloc(strlen(localhost)+strlen(Url->path)+strlen(sorttype[0])+16);
  176.     sprintf(relocate,"http://%s%s?sort=%s",localhost,Url->path,sorttype[0]);
  177.     HTMLMessage(fd,301,"WWWOFFLE Index Redirect",relocate,"IndexRedirect",
  178.                 "url",Url->pathp,
  179.                 "link",relocate+7+strlen(localhost),
  180.                 NULL);
  181.     free(relocate);
  182.     free(localhost);
  183.    }
  184.  else
  185.    {
  186.     HTMLMessageHead(fd,200,"WWWOFFLE Index",
  187.                     NULL);
  188.     HTMLMessageBody(fd,"Index-Head",
  189.                     "type",prevtime?"prevtime":proto,
  190.                     "subtype",prevtime?proto+8:host,
  191.                     "sort",sorttype[sort],
  192.                     "delete" ,delopt?"&delete":"",
  193.                     "refresh",refopt?"&refresh":"",
  194.                     "monitor",monopt?"&monitor":"",
  195.                     "all"    ,allopt?"&all":"",
  196.                     NULL);
  197.     if(outgoing)
  198.        IndexOutgoing(fd,sort,delopt,refopt,monopt,allopt);
  199.     else if(monitor)
  200.        IndexMonitor(fd,sort,delopt,refopt,monopt,allopt);
  201.     else if(lasttime || prevtime)
  202.        IndexLastTime(fd,proto,sort,delopt,refopt,monopt,allopt);
  203.     else if(latest)
  204.        IndexLatest(fd,sort,delopt,refopt,monopt,allopt);
  205.     else if(protocol && !*host)
  206.        IndexProtocol(fd,proto,sort,delopt,refopt,monopt,allopt);
  207.     else if(protocol && *host)
  208.        IndexHost(fd,proto,host,sort,delopt,refopt,monopt,allopt);
  209.     else
  210.        IndexRoot(fd);
  211.     HTMLMessageBody(fd,"Index-Tail",
  212.                     "type",prevtime?"prevtime":proto,
  213.                     "subtype",prevtime?proto+8:host,
  214.                     "sort",sorttype[sort],
  215.                     "delete" ,delopt?"&delete":"",
  216.                     "refresh",refopt?"&refresh":"",
  217.                     "monitor",monopt?"&monitor":"",
  218.                     "all"    ,allopt?"&all":"",
  219.                     NULL);
  220.    }
  221.  free(newpath);
  222. }
  223. /*++++++++++++++++++++++++++++++++++++++
  224.   Index the root of the cache.
  225.   int fd The file descriptor to write to.
  226.   ++++++++++++++++++++++++++++++++++++++*/
  227. static void IndexRoot(int fd)
  228. {
  229.  HTMLMessageBody(fd,"IndexRoot-Body",NULL);
  230. }
  231. /*++++++++++++++++++++++++++++++++++++++
  232.   Index the hosts for one protocol in the cache.
  233.   int fd The file descriptor to write to.
  234.   char *proto The protocol to index.
  235.   SortMode mode The sort mode to use.
  236.   int delopt The option to display the delete button in the index.
  237.   int refopt The option to display the refresh buttons in the index.
  238.   int monopt The option to display the monitor button in the index.
  239.   int allopt The option to show all pages including DontIndex ones.
  240.   ++++++++++++++++++++++++++++++++++++++*/
  241. static void IndexProtocol(int fd,char *proto,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  242. {
  243.  DIR *dir;
  244.  struct dirent* ent;
  245.  int i;
  246.  char total[8],indexed[8],notindexed[8];
  247.  int lastdays=0,lasthours=0;
  248.  /* Open the spool directory. */
  249.  if(chdir(proto))
  250.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; not indexed.",proto);
  251.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  252.  dir=opendir(".");
  253.  if(!dir)
  254.    {PrintMessage(Warning,"Cannot open spool directory '%s' [%!s]; index failed.",proto);chdir("..");
  255.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  256.  ent=readdir(dir);  /* skip .  */
  257.  if(!ent)
  258.    {PrintMessage(Warning,"Cannot read spool directory '%s' [%!s]; index failed.",proto);closedir(dir);chdir("..");
  259.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  260.  ent=readdir(dir);  /* skip .. */
  261.  /* Get all of the host sub-directories. */
  262.  while((ent=readdir(dir)))
  263.     add_dir(ent->d_name,mode);
  264.  closedir(dir);
  265.  chdir("..");
  266.  /* Sort the files. */
  267.  if(mode==MTime || mode==ATime || mode==Dated)
  268.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  269.  else if(mode==Alpha || mode==Type)
  270.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  271.  else if(mode==Domain)
  272.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_domain);
  273.  /* Output the page. */
  274.  sprintf(total,"%d",nfiles);
  275.  HTMLMessageBody(fd,"IndexProtocol-Head",
  276.                  "proto",proto,
  277.                  "total",total,
  278.                  "sort",sorttype[mode],
  279.                  "delete" ,delopt?"&delete":"",
  280.                  "refresh",refopt?"&refresh":"",
  281.                  "monitor",monopt?"&monitor":"",
  282.                  "all"    ,allopt?"&all":"",
  283.                  NULL);
  284.  for(i=0;i<nfiles;i++)
  285.    {
  286.     if(mode==Dated)
  287.        dated_separator(fd,i,&lastdays,&lasthours);
  288.     HTMLMessageBody(fd,"IndexProtocol-Body",
  289.                     "proto",proto,
  290.                     "host",files[i]->name,
  291.                     "sort",sorttype[mode],
  292.                     "delete" ,delopt?"&delete":"",
  293.                     "refresh",refopt?"&refresh":"",
  294.                     "monitor",monopt?"&monitor":"",
  295.                     "all"    ,allopt?"&all":"",
  296.                     NULL);
  297.     free(files[i]->name);
  298.     free(files[i]);
  299.    }
  300.  sprintf(indexed   ,"%d",nfiles);
  301.  sprintf(notindexed,"%d",0);
  302.  HTMLMessageBody(fd,"IndexProtocol-Tail",
  303.                  "proto",proto,
  304.                  "total",total,
  305.                  "indexed",indexed,
  306.                  "notindexed",notindexed,
  307.                  "sort",sorttype[mode],
  308.                  "delete" ,delopt?"&delete":"",
  309.                  "refresh",refopt?"&refresh":"",
  310.                  "monitor",monopt?"&monitor":"",
  311.                  "all"    ,allopt?"&all":"",
  312.                  NULL);
  313.  /* Tidy up and exit */
  314.  if(files)
  315.     free(files);
  316.  files=NULL;
  317.  nfiles=0;
  318. }
  319. /*++++++++++++++++++++++++++++++++++++++
  320.   Create an index of the pages on a host.
  321.   int fd The file descriptor to write to.
  322.   char *proto The protocol to index.
  323.   char *host The name of the subdirectory.
  324.   SortMode mode The sort mode to use.
  325.   int delopt The option to display the delete button in the index.
  326.   int refopt The option to display the refresh buttons in the index.
  327.   int monopt The option to display the monitor button in the index.
  328.   int allopt The option to show all pages including DontIndex ones.
  329.   ++++++++++++++++++++++++++++++++++++++*/
  330. static void IndexHost(int fd,char *proto,char *host,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  331. {
  332.  DIR *dir;
  333.  struct dirent* ent;
  334.  int i,nindexed=0;
  335.  char total[8],indexed[8],notindexed[8];
  336.  int lastdays=0,lasthours=0;
  337.  /* Open the spool subdirectory. */
  338.  if(chdir(proto))
  339.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; not indexed.",proto);
  340.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  341.  /* Open the spool subdirectory. */
  342. #if defined(__CYGWIN__)
  343.  if(strchr(host,':'))
  344.    {
  345.     char *colon=strchr(host,':');
  346.     *colon='!';
  347.    }
  348. #endif
  349.  if(chdir(host))
  350.    {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s]; not indexed.",proto,host);chdir("..");
  351.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  352.  dir=opendir(".");
  353.  if(!dir)
  354.    {PrintMessage(Warning,"Cannot open directory '%s/%s' [%!s]; not indexed.",proto,host);chdir("../..");
  355.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  356.  ent=readdir(dir);  /* skip .  */
  357.  if(!ent)
  358.    {PrintMessage(Warning,"Cannot read directory '%s/%s' [%!s]; not indexed.",proto,host);closedir(dir);chdir("../..");
  359.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  360.  ent=readdir(dir);  /* skip .. */
  361. #if defined(__CYGWIN__)
  362.  if(strchr(host,'!'))
  363.    {
  364.     char *bang=strchr(host,'!');
  365.     *bang=':';
  366.    }
  367. #endif
  368.  /* Add all of the file names. */
  369.  while((ent=readdir(dir)))
  370.     add_file(ent->d_name,mode);
  371.  closedir(dir);
  372.  chdir("../..");
  373.  /* Sort the files. */
  374.  if(mode==MTime || mode==ATime || mode==Dated)
  375.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  376.  else if(mode==Alpha || mode==Domain)
  377.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  378.  else if(mode==Type)
  379.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_type);
  380.  /* Output the page. */
  381.  sprintf(total,"%d",nfiles);
  382.  HTMLMessageBody(fd,"IndexHost-Head",
  383.                  "proto",proto,
  384.                  "host",host,
  385.                  "total",total,
  386.                  "sort",sorttype[mode],
  387.                  "delete" ,delopt?"&delete":"",
  388.                  "refresh",refopt?"&refresh":"",
  389.                  "monitor",monopt?"&monitor":"",
  390.                  "all"    ,allopt?"&all":"",
  391.                  NULL);
  392.  for(i=0;i<nfiles;i++)
  393.    {
  394.     if(allopt || !IsNotIndexed(files[i]->url,"host"))
  395.       {
  396.        char *decurl=URLDecode(files[i]->url->pathp,0);
  397.        if(mode==Dated)
  398.           dated_separator(fd,i,&lastdays,&lasthours);
  399.        HTMLMessageBody(fd,"IndexHost-Body",
  400.                        "url",files[i]->url->name,
  401.                        "link",files[i]->url->link,
  402.                        "item",decurl,
  403.                        "delete" ,delopt?"&delete":"",
  404.                        "refresh",refopt?"&refresh":"",
  405.                        "monitor",monopt?"&monitor":"",
  406.                        NULL);
  407.        free(decurl);
  408.        nindexed++;
  409.       }
  410.     FreeURL(files[i]->url);
  411.     free(files[i]);
  412.    }
  413.  sprintf(indexed   ,"%d",nindexed);
  414.  sprintf(notindexed,"%d",nfiles-nindexed);
  415.  HTMLMessageBody(fd,"IndexHost-Tail",
  416.                  "proto",proto,
  417.                  "host",host,
  418.                  "total",total,
  419.                  "indexed",indexed,
  420.                  "notindexed",notindexed,
  421.                  "sort",sorttype[mode],
  422.                  "delete" ,delopt?"&delete":"",
  423.                  "refresh",refopt?"&refresh":"",
  424.                  "monitor",monopt?"&monitor":"",
  425.                  "all"    ,allopt?"&all":"",
  426.                  NULL);
  427.  /* Tidy up and exit */
  428.  if(files)
  429.     free(files);
  430.  files=NULL;
  431.  nfiles=0;
  432. }
  433. /*++++++++++++++++++++++++++++++++++++++
  434.   Create an index of the requests that are waiting in the outgoing directory.
  435.   int fd The file descriptor to write to.
  436.   SortMode mode The method to use to sort the names.
  437.   int delopt The option to display the delete button in the index.
  438.   int refopt The option to display the refresh buttons in the index.
  439.   int monopt The option to display the monitor button in the index.
  440.   int allopt The option to show all pages including DontIndex ones.
  441.   ++++++++++++++++++++++++++++++++++++++*/
  442. static void IndexOutgoing(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  443. {
  444.  DIR *dir;
  445.  struct dirent* ent;
  446.  int i,nindexed=0;
  447.  char total[8],indexed[8],notindexed[8];
  448.  int lastdays=0,lasthours=0;
  449.  /* Open the outgoing subdirectory. */
  450.  if(chdir("outgoing"))
  451.    {PrintMessage(Warning,"Cannot change to directory 'outgoing' [%!s]; not indexed.");
  452.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  453.  dir=opendir(".");
  454.  if(!dir)
  455.    {PrintMessage(Warning,"Cannot open directory 'outgoing' [%!s]; not indexed.");chdir("..");
  456.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  457.  ent=readdir(dir);  /* skip .  */
  458.  if(!ent)
  459.    {PrintMessage(Warning,"Cannot read directory 'outgoing' [%!s]; not indexed.");closedir(dir);chdir("..");
  460.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  461.  ent=readdir(dir);  /* skip .. */
  462.  /* Add all of the file names. */
  463.  while((ent=readdir(dir)))
  464.     add_file(ent->d_name,mode);
  465.  closedir(dir);
  466.  chdir("..");
  467.  /* Sort the files. */
  468.  if(mode==MTime || mode==ATime || mode==Dated)
  469.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  470.  else if(mode==Alpha)
  471.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  472.  else if(mode==Type)
  473.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_type);
  474.  else if(mode==Domain)
  475.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_domain);
  476.  /* Output the page. */
  477.  sprintf(total,"%d",nfiles);
  478.  HTMLMessageBody(fd,"IndexOutgoing-Head",
  479.                  "total",total,
  480.                  "sort",sorttype[mode],
  481.                  "delete" ,delopt?"&delete":"",
  482.                  "refresh",refopt?"&refresh":"",
  483.                  "monitor",monopt?"&monitor":"",
  484.                  "all"    ,allopt?"&all":"",
  485.                  NULL);
  486.  for(i=0;i<nfiles;i++)
  487.    {
  488.     if(allopt || !IsNotIndexed(files[i]->url,"outgoing"))
  489.       {
  490.        char *decurl=URLDecode(files[i]->url->name,0);
  491.        if(mode==Dated)
  492.           dated_separator(fd,i,&lastdays,&lasthours);
  493.        HTMLMessageBody(fd,"IndexOutgoing-Body",
  494.                        "url",files[i]->url->name,
  495.                        "link",files[i]->url->link,
  496.                        "item",decurl,
  497.                        "delete" ,delopt?"&delete":"",
  498.                        "refresh",refopt?"&refresh":"",
  499.                        "monitor",monopt?"&monitor":"",
  500.                        NULL);
  501.        free(decurl);
  502.        nindexed++;
  503.       }
  504.     FreeURL(files[i]->url);
  505.     free(files[i]);
  506.    }
  507.  sprintf(indexed   ,"%d",nindexed);
  508.  sprintf(notindexed,"%d",nfiles-nindexed);
  509.  HTMLMessageBody(fd,"IndexOutgoing-Tail",
  510.                  "total",total,
  511.                  "indexed",indexed,
  512.                  "notindexed",notindexed,
  513.                  "sort",sorttype[mode],
  514.                  "delete" ,delopt?"&delete":"",
  515.                  "refresh",refopt?"&refresh":"",
  516.                  "monitor",monopt?"&monitor":"",
  517.                  "all"    ,allopt?"&all":"",
  518.                  NULL);
  519.  /* Tidy up and exit */
  520.  if(files)
  521.     free(files);
  522.  files=NULL;
  523.  nfiles=0;
  524. }
  525. /*++++++++++++++++++++++++++++++++++++++
  526.   Create an index of the requests that are in the monitor directory.
  527.   int fd The file descriptor to write to.
  528.   SortMode mode The method to use to sort the names.
  529.   int delopt The option to display the delete button in the index.
  530.   int refopt The option to display the refresh buttons in the index.
  531.   int monopt The option to display the monitor button in the index.
  532.   int allopt The option to show all pages including DontIndex ones.
  533.   ++++++++++++++++++++++++++++++++++++++*/
  534. static void IndexMonitor(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  535. {
  536.  DIR *dir;
  537.  struct dirent* ent;
  538.  int i,nindexed=0;
  539.  char total[8],indexed[8],notindexed[8];
  540.  int lastdays=0,lasthours=0;
  541.  /* Open the monitor subdirectory. */
  542.  if(chdir("monitor"))
  543.    {PrintMessage(Warning,"Cannot change to directory 'monitor' [%!s]; not indexed.");
  544.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  545.  dir=opendir(".");
  546.  if(!dir)
  547.    {PrintMessage(Warning,"Cannot open directory 'monitor' [%!s]; not indexed.");chdir("..");
  548.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  549.  ent=readdir(dir);  /* skip .  */
  550.  if(!ent)
  551.    {PrintMessage(Warning,"Cannot read directory 'monitor' [%!s]; not indexed.");closedir(dir);chdir("..");
  552.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  553.  ent=readdir(dir);  /* skip .. */
  554.  /* Add all of the file names. */
  555.  while((ent=readdir(dir)))
  556.     add_file(ent->d_name,mode);
  557.  closedir(dir);
  558.  chdir("..");
  559.  /* Sort the files. */
  560.  if(mode==MTime || mode==ATime || mode==Dated)
  561.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  562.  else if(mode==Alpha)
  563.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  564.  else if(mode==Type)
  565.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_type);
  566.  else if(mode==Domain)
  567.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_domain);
  568.  /* Output the page. */
  569.  sprintf(total,"%d",nfiles);
  570.  HTMLMessageBody(fd,"IndexMonitor-Head",
  571.                  "total",total,
  572.                  "sort",sorttype[mode],
  573.                  "delete" ,delopt?"&delete":"",
  574.                  "refresh",refopt?"&refresh":"",
  575.                  "monitor",monopt?"&monitor":"",
  576.                  "all"    ,allopt?"&all":"",
  577.                  NULL);
  578.  for(i=0;i<nfiles;i++)
  579.    {
  580.     if(allopt || !IsNotIndexed(files[i]->url,"monitor"))
  581.       {
  582.        char *decurl=URLDecode(files[i]->url->name,0);
  583.        int last,next;
  584.        char laststr[8],nextstr[8];
  585.        MonitorTimes(files[i]->url,&last,&next);
  586.        if(last>=(31*24))
  587.           sprintf(laststr,"31+");
  588.        else
  589.           sprintf(laststr,"%d:%d",last/24,last%24);
  590.        if(next>=(31*24))
  591.           sprintf(nextstr,"31+");
  592.        else
  593.           sprintf(nextstr,"%d:%d",next/24,next%24);
  594.        if(mode==Dated)
  595.           dated_separator(fd,i,&lastdays,&lasthours);
  596.        HTMLMessageBody(fd,"IndexMonitor-Body",
  597.                        "url",files[i]->url->name,
  598.                        "link",files[i]->url->link,
  599.                        "item",decurl,
  600.                        "last",laststr,
  601.                        "next",nextstr,
  602.                        "delete" ,delopt?"&delete":"",
  603.                        "refresh",refopt?"&refresh":"",
  604.                        "monitor",monopt?"&monitor":"",
  605.                        NULL);
  606.        free(decurl);
  607.        nindexed++;
  608.       }
  609.     FreeURL(files[i]->url);
  610.     free(files[i]);
  611.    }
  612.  sprintf(indexed   ,"%d",nindexed);
  613.  sprintf(notindexed,"%d",nfiles-nindexed);
  614.  HTMLMessageBody(fd,"IndexMonitor-Tail",
  615.                  "total",total,
  616.                  "indexed",indexed,
  617.                  "notindexed",notindexed,
  618.                  "sort",sorttype[mode],
  619.                  "delete" ,delopt?"&delete":"",
  620.                  "refresh",refopt?"&refresh":"",
  621.                  "monitor",monopt?"&monitor":"",
  622.                  "all"    ,allopt?"&all":"",
  623.                  NULL);
  624.  /* Tidy up and exit */
  625.  if(files)
  626.     free(files);
  627.  files=NULL;
  628.  nfiles=0;
  629. }
  630. /*++++++++++++++++++++++++++++++++++++++
  631.   Create an index of the pages that were got last time online.
  632.   int fd The file descriptor to write to.
  633.   char *name The name of the directory.
  634.   SortMode mode The method to use to sort the names.
  635.   int delopt The option to display the delete button in the index.
  636.   int refopt The option to display the refresh buttons in the index.
  637.   int monopt The option to display the monitor button in the index.
  638.   int allopt The option to show all pages including DontIndex ones.
  639.   ++++++++++++++++++++++++++++++++++++++*/
  640. static void IndexLastTime(int fd,char *name,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  641. {
  642.  DIR *dir;
  643.  struct dirent* ent;
  644.  int i,nindexed=0;
  645.  char total[8],indexed[8],notindexed[8];
  646.  int lastdays=0,lasthours=0;
  647.  /* Open the lasttime subdirectory. */
  648.  if(chdir(name))
  649.    {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; not indexed.",name);
  650.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  651.  dir=opendir(".");
  652.  if(!dir)
  653.    {PrintMessage(Warning,"Cannot open directory '%s' [%!s]; not indexed.",name);chdir("..");
  654.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  655.  ent=readdir(dir);  /* skip .  */
  656.  if(!ent)
  657.    {PrintMessage(Warning,"Cannot read directory '%s' [%!s]; not indexed.",name);closedir(dir);chdir("..");
  658.    HTMLMessageBody(fd,"IndexError-Body",NULL);return;}
  659.  ent=readdir(dir);  /* skip .. */
  660.  /* Add all of the file names. */
  661.  while((ent=readdir(dir)))
  662.     add_file(ent->d_name,mode);
  663.  closedir(dir);
  664.  chdir("..");
  665.  /* Sort the files. */
  666.  if(mode==MTime || mode==ATime || mode==Dated)
  667.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  668.  else if(mode==Alpha)
  669.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  670.  else if(mode==Type)
  671.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_type);
  672.  else if(mode==Domain)
  673.     qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_domain);
  674.  /* Output the page. */
  675.  sprintf(total,"%d",nfiles);
  676.  HTMLMessageBody(fd,"IndexLastTime-Head",
  677.                  "number",name+8,
  678.                  "total",total,
  679.                  "sort",sorttype[mode],
  680.                  "delete" ,delopt?"&delete":"",
  681.                  "refresh",refopt?"&refresh":"",
  682.                  "monitor",monopt?"&monitor":"",
  683.                  "all"    ,allopt?"&all":"",
  684.                  NULL);
  685.  for(i=0;i<nfiles;i++)
  686.    {
  687.     if(allopt || !IsNotIndexed(files[i]->url,"latest"))
  688.       {
  689.        char *decurl=URLDecode(files[i]->url->name,0);
  690.        if(mode==Dated)
  691.           dated_separator(fd,i,&lastdays,&lasthours);
  692.        HTMLMessageBody(fd,"IndexLastTime-Body",
  693.                        "url",files[i]->url->name,
  694.                        "link",files[i]->url->link,
  695.                        "item",decurl,
  696.                        "delete" ,delopt?"&delete":"",
  697.                        "refresh",refopt?"&refresh":"",
  698.                        "monitor",monopt?"&monitor":"",
  699.                        NULL);
  700.        free(decurl);
  701.        nindexed++;
  702.       }
  703.     FreeURL(files[i]->url);
  704.     free(files[i]);
  705.    }
  706.  sprintf(indexed   ,"%d",nindexed);
  707.  sprintf(notindexed,"%d",nfiles-nindexed);
  708.  HTMLMessageBody(fd,"IndexLastTime-Tail",
  709.                  "number",name+8,
  710.                  "total",total,
  711.                  "indexed",indexed,
  712.                  "notindexed",notindexed,
  713.                  "sort",sorttype[mode],
  714.                  "delete" ,delopt?"&delete":"",
  715.                  "refresh",refopt?"&refresh":"",
  716.                  "monitor",monopt?"&monitor":"",
  717.                  "all"    ,allopt?"&all":"",
  718.                  NULL);
  719.  /* Tidy up and exit */
  720.  if(files)
  721.     free(files);
  722.  files=NULL;
  723.  nfiles=0;
  724. }
  725. /*++++++++++++++++++++++++++++++++++++++
  726.   Create an index of the latest pages.
  727.   int fd The file descriptor to write to.
  728.   SortMode mode The method to use to sort the names.
  729.   int delopt The option to display the delete button in the index.
  730.   int refopt The option to display the refresh buttons in the index.
  731.   int monopt The option to display the monitor button in the index.
  732.   int allopt The option to show all pages including DontIndex ones.
  733.   ++++++++++++++++++++++++++++++++++++++*/
  734. static void IndexLatest(int fd,SortMode mode,int delopt,int refopt, int monopt,int allopt)
  735. {
  736.  int i,p,nindexed=0;
  737.  char total[8],indexed[8],notindexed[8];
  738.  int lastdays=0,lasthours=0;
  739.  earliest=now-IndexLatestDays*24*3600;
  740.  if(IndexLatestDays>0)
  741.    {
  742.     /* Add all of the files in the sub directories. */
  743.     for(p=0;p<NProtocols;p++)
  744.       {
  745.        struct stat buf;
  746.        if(!lstat(Protocols[p].name,&buf) && S_ISDIR(buf.st_mode))
  747.          {
  748.           DIR *dir2;
  749.           struct dirent* ent2;
  750.           if(chdir(Protocols[p].name))
  751.             {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; not indexed.",Protocols[p].name);continue;}
  752.           /* Open the spool directory. */
  753.           dir2=opendir(".");
  754.           if(!dir2)
  755.             {PrintMessage(Warning,"Cannot open directory '%s' [%!s]; not indexed.",Protocols[p].name);chdir("..");continue;}
  756.           ent2=readdir(dir2);  /* skip .  */
  757.           if(!ent2)
  758.             {PrintMessage(Warning,"Cannot read directory '%s' [%!s]; index failed.",Protocols[p].name);closedir(dir2);chdir("..");continue;}
  759.           ent2=readdir(dir2);  /* skip .. */
  760.           /* Print all of the sub directories. */
  761.           while((ent2=readdir(dir2)))
  762.             {
  763.              struct stat buf2;
  764.              if(lstat(ent2->d_name,&buf2))
  765.                 PrintMessage(Inform,"Cannot stat file '%s' [%!s]; race condition?",ent2->d_name);
  766.              else
  767.                 if(S_ISDIR(buf2.st_mode) && buf2.st_mtime>earliest)
  768.                   {
  769.                    DIR *dir3;
  770.                    struct dirent* ent3;
  771.                    struct utimbuf utbuf;
  772.                    if(chdir(ent2->d_name))
  773.                      {PrintMessage(Warning,"Cannot change to directory '%s/%s' [%!s]; not indexed.",Protocols[p].name,ent2->d_name);continue;}
  774.                    dir3=opendir(".");
  775.                    if(!dir3)
  776.                      {PrintMessage(Warning,"Cannot open directory '%s/%s' [%!s]; not indexed.",Protocols[p].name,ent2->d_name);chdir("..");continue;}
  777.                    ent3=readdir(dir3);  /* skip .  */
  778.                    if(!ent3)
  779.                      {PrintMessage(Warning,"Cannot read directory '%s/%s' [%!s]; not indexed.",Protocols[p].name,ent2->d_name);closedir(dir3);chdir("..");continue;}
  780.                    ent3=readdir(dir3);  /* skip .. */
  781.                    while((ent3=readdir(dir3)))
  782.                       add_file(ent3->d_name,mode);
  783.                    closedir(dir3);
  784.                    chdir("..");
  785.                    utbuf.actime=buf2.st_atime;
  786.                    utbuf.modtime=buf2.st_mtime;
  787.                    utime(ent2->d_name,&utbuf);
  788.                   }
  789.             }
  790.           closedir(dir2);
  791.           chdir("..");
  792.          }
  793.       }
  794.     /* Sort the files. */
  795.     if(mode==MTime || mode==ATime || mode==Dated)
  796.        qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_time);
  797.     else if(mode==Alpha)
  798.        qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_alpha);
  799.     else if(mode==Type)
  800.        qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_type);
  801.     else if(mode==Domain)
  802.        qsort(files,nfiles,sizeof(FileIndex*),(int (*)(const void*,const void*))sort_domain);
  803.    }
  804.  /* Output the page. */
  805.  sprintf(total,"%d",nfiles);
  806.  HTMLMessageBody(fd,"IndexLatest-Head",
  807.                  "total",total,
  808.                  "sort",sorttype[mode],
  809.                  "delete" ,delopt?"&delete":"",
  810.                  "refresh",refopt?"&refresh":"",
  811.                  "monitor",monopt?"&monitor":"",
  812.                  "all"    ,allopt?"&all":"",
  813.                  NULL);
  814.  for(i=0;i<nfiles;i++)
  815.    {
  816.     if(allopt || !IsNotIndexed(files[i]->url,"latest"))
  817.       {
  818.        char *decurl=URLDecode(files[i]->url->name,0);
  819.        if(mode==Dated)
  820.           dated_separator(fd,i,&lastdays,&lasthours);
  821.        HTMLMessageBody(fd,"IndexLatest-Body",
  822.                        "url",files[i]->url->name,
  823.                        "link",files[i]->url->link,
  824.                        "item",decurl,
  825.                        "delete" ,delopt?"&delete":"",
  826.                        "refresh",refopt?"&refresh":"",
  827.                        "monitor",monopt?"&monitor":"",
  828.                        NULL);
  829.        free(decurl);
  830.        nindexed++;
  831.       }
  832.     FreeURL(files[i]->url);
  833.     free(files[i]);
  834.    }
  835.  sprintf(indexed   ,"%d",nindexed);
  836.  sprintf(notindexed,"%d",nfiles-nindexed);
  837.  HTMLMessageBody(fd,"IndexLatest-Tail",
  838.                  "total",total,
  839.                  "indexed",indexed,
  840.                  "notindexed",notindexed,
  841.                  "sort",sorttype[mode],
  842.                  "delete" ,delopt?"&delete":"",
  843.                  "refresh",refopt?"&refresh":"",
  844.                  "monitor",monopt?"&monitor":"",
  845.                  "all"    ,allopt?"&all":"",
  846.                  NULL);
  847.  /* Tidy up and exit */
  848.  if(files)
  849.     free(files);
  850.  files=NULL;
  851.  nfiles=0;
  852. }
  853. /*++++++++++++++++++++++++++++++++++++++
  854.   Add a directory to the list.
  855.   char *name The name of the directory.
  856.   SortMode mode The sort mode.
  857.   ++++++++++++++++++++++++++++++++++++++*/
  858. static void add_dir(char *name,SortMode mode)
  859. {
  860.  struct stat buf;
  861.  if(stat(name,&buf))
  862.    {PrintMessage(Inform,"Cannot stat directory '%s' [%!s]; race condition?",name);return;}
  863.  else if(S_ISDIR(buf.st_mode))
  864.    {
  865.     if(!(nfiles%16))
  866.       {
  867.        if(!files)
  868.           files=(FileIndex**)malloc(16*sizeof(FileIndex*));
  869.        else
  870.           files=(FileIndex**)realloc(files,(nfiles+16)*sizeof(FileIndex*));
  871.       }
  872.     files[nfiles]=(FileIndex*)malloc(sizeof(FileIndex));
  873. #if defined(__CYGWIN__)
  874.     if(strchr(name,'!'))
  875.       {
  876.        char *bang=strchr(name,'!');
  877.        *bang=':';
  878.       }
  879. #endif
  880.     files[nfiles]->name=(char*)malloc(strlen(name)+1);
  881.     strcpy(files[nfiles]->name,name);
  882.     if(mode==Domain)
  883.        files[nfiles]->host=files[nfiles]->name;
  884.     else if(mode==Type)
  885.        files[nfiles]->type="";
  886.     else if(mode==MTime || mode==Dated)
  887.        files[nfiles]->time=buf.st_mtime;
  888.     else if(mode==ATime)
  889.        files[nfiles]->time=buf.st_atime;
  890.     nfiles++;
  891.    }
  892. }
  893. /*++++++++++++++++++++++++++++++++++++++
  894.   Add a file to the list.
  895.   char *name The name of the file.
  896.   SortMode mode The sort mode.
  897.   ++++++++++++++++++++++++++++++++++++++*/
  898. static void add_file(char *name,SortMode mode)
  899. {
  900.  char *url=NULL;
  901.  struct stat buf;
  902.  if((*name!='D' && *name!='O') || name[strlen(name)-1]=='~')
  903.     return;
  904.  url=FileNameToURL(name);
  905.  if(!url)
  906.     return;
  907.  if(stat(name,&buf))
  908.    {PrintMessage(Inform,"Cannot stat file '%s' [%!s]; race condition?",name);return;}
  909.  else if(S_ISREG(buf.st_mode) && (mode!=Dated || buf.st_mtime>earliest))
  910.    {
  911.     if(!(nfiles%16))
  912.       {
  913.        if(!files)
  914.           files=(FileIndex**)malloc(16*sizeof(FileIndex*));
  915.        else
  916.           files=(FileIndex**)realloc(files,(nfiles+16)*sizeof(FileIndex*));
  917.       }
  918.     files[nfiles]=(FileIndex*)malloc(sizeof(FileIndex));
  919.     files[nfiles]->url=SplitURL(url);
  920.     files[nfiles]->name=files[nfiles]->url->name;
  921.     if(mode==Domain)
  922.        files[nfiles]->host=files[nfiles]->url->host;
  923.     else if(mode==Type)
  924.       {
  925.        char *p=files[nfiles]->url->path+strlen(files[nfiles]->url->path);
  926.        for(;p>=files[nfiles]->url->path;p--)
  927.           if(*p=='.')
  928.             {files[nfiles]->type=p;break;}
  929.           else if(*p=='/')
  930.             {files[nfiles]->type="";break;}
  931.       }
  932.     else if(mode==MTime || mode==Dated)
  933.        files[nfiles]->time=buf.st_mtime;
  934.     else if(mode==ATime)
  935.        files[nfiles]->time=buf.st_atime;
  936.     nfiles++;
  937.    }
  938. }
  939. /*++++++++++++++++++++++++++++++++++++++
  940.   Write out a date separator for the dated format if needed.
  941.   int fd The file to write to.
  942.   int file The number of the file in the list.
  943.   int *lastdays The age of the previous file in days.
  944.   int *lasthours The age of the previous file in hours.
  945.   ++++++++++++++++++++++++++++++++++++++*/
  946. static void dated_separator(int fd,int file,int *lastdays,int *lasthours)
  947. {
  948.  int days=(now-files[file]->time)/(24*3600),hours=(now-files[file]->time)/3600;
  949.  if(*lastdays<days)
  950.    {
  951.     char daystr[8];
  952.     sprintf(daystr,"%d",days-*lastdays);
  953.     HTMLMessageBody(fd,"IndexSeparator-Body",
  954.                     "days",daystr,
  955.                     NULL);
  956.    }
  957.  else if(file && *lasthours<(hours-1))
  958.    {
  959.     HTMLMessageBody(fd,"IndexSeparator-Body",
  960.                     "days","",
  961.                     NULL);
  962.    }
  963.  *lastdays=days;
  964.  *lasthours=hours;
  965. }
  966. /*++++++++++++++++++++++++++++++++++++++
  967.   Used to sort the files into alphabetical order.
  968.   int sort_alpha Returns the comparison of the pointers to strings.
  969.   FileIndex **a The first FileIndex.
  970.   FileIndex **b The second FileIndex.
  971.   ++++++++++++++++++++++++++++++++++++++*/
  972. static int sort_alpha(FileIndex **a,FileIndex **b)
  973. {
  974.  char *an=(*a)->name;
  975.  char *bn=(*b)->name;
  976.  return(strcmp(an,bn));
  977. }
  978. /*++++++++++++++++++++++++++++++++++++++
  979.   Used to sort the files into type (file extension) order.
  980.   int sort_type Returns the comparison of the pointers to strings.
  981.   FileIndex **a The first FileIndex.
  982.   FileIndex **b The second FileIndex.
  983.   ++++++++++++++++++++++++++++++++++++++*/
  984. static int sort_type(FileIndex **a,FileIndex **b)
  985. {
  986.  char *an=(*a)->name,*at=(*a)->type;
  987.  char *bn=(*b)->name,*bt=(*b)->type;
  988.  int sort1=strcmp(at,bt);
  989.  if(sort1==0)
  990.     return(strcmp(an,bn));
  991.  else
  992.     return(sort1);
  993. }
  994. /*++++++++++++++++++++++++++++++++++++++
  995.   Used to sort the files into domain order.
  996.   int sort_domain Returns the comparison of the pointers to strings.
  997.   FileIndex **a The first FileIndex.
  998.   FileIndex **b The second FileIndex.
  999.   ++++++++++++++++++++++++++++++++++++++*/
  1000. static int sort_domain(FileIndex **a,FileIndex **b)
  1001. {
  1002.  char *ap=(*a)->host+strlen((*a)->host);
  1003.  char *bp=(*b)->host+strlen((*b)->host);
  1004.  int chosen=0;
  1005.  do
  1006.    {
  1007.     ap--;
  1008.     bp--;
  1009.     while(ap>(*a)->host && *ap!='.' && *ap!='/')
  1010.        ap--;
  1011.     while(bp>(*b)->host && *bp!='.' && *bp!='/')
  1012.        bp--;
  1013.     chosen=strcmp(ap,bp);
  1014.    }
  1015.  while(!chosen);
  1016.  return(chosen);
  1017. }
  1018. /*++++++++++++++++++++++++++++++++++++++
  1019.   Used to sort the files into time order.
  1020.   int sort_time Returns the comparison of the times.
  1021.   FileIndex **a The first FileIndex.
  1022.   FileIndex **b The second FileIndex.
  1023.   ++++++++++++++++++++++++++++++++++++++*/
  1024. static int sort_time(FileIndex **a,FileIndex **b)
  1025. {
  1026.  long at=(*a)->time;
  1027.  long bt=(*b)->time;
  1028.  return(bt-at);
  1029. }