]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - index.c
Remove any limit on the maximum URL length (bugs remain)
[thirdparty/sarg.git] / index.c
diff --git a/index.c b/index.c
index e11fb4474f30203ac1a0e9333f912dd9c1b84cf4..9b7a82bc8b4b8b3df585a289b5a614df5392fe40 100644 (file)
--- a/index.c
+++ b/index.c
@@ -1,10 +1,11 @@
 /*
- * AUTHOR: Pedro Lineu Orso                         pedro.orso@gmail.com
- *                                                            1998, 2008
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
+ *                                                            1998, 2010
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
+ * Support:
+ *     http://sourceforge.net/projects/sarg/forums/forum/363374
  * ---------------------------------------------------------------------
  *
  *  This program is free software; you can redistribute it and/or modify
 #include "include/conf.h"
 #include "include/defs.h"
 
+static void make_date_index(void);
+static void make_file_index(void);
+static void file_index_to_date_index(const char *entry);
+static void date_index_to_file_index(const char *entry);
+
 void make_index(void)
 {
-
-   FILE *fp_ou, *fp_ou2, *fp_ou3, *fp_tmp, *fp_tmp2, *fp_tmp3;
-   DIR *dirp, *dirp2, *dirp3;
+   DIR *dirp;
    struct dirent *direntp;
-   struct dirent *direntp2;
-   struct dirent *direntp3;
-   char html[MAXLEN];
    char wdir[MAXLEN];
-   char wdir_tmp[MAXLEN];
-   char wdir_tmp2[MAXLEN];
-   char wdir_tmp3[MAXLEN];
-   char newname[512];
-   char month[4];
-   char period[80];
-   char data[80];
-   char tuser[20];
-   char tbytes[20];
-   char media[20];
-   char ftime[128];
-   char day[16], mon[16], year[40], hour[10];
-   char *str;
-   int cstatus;
-   int iyear, imonth, iday, ihour, iminute, isecond, idst;
-   char y1[5], y2[5];
-   char d1[3], d2[3];
-   char m1[4], m2[4];
-   struct getwordstruct gwarea;
 
-   if(LastLog[0] != '\0') mklastlog(outdir);
-
-   sprintf(wdir,"%sindex.html",outdir);
-   sprintf(wdir_tmp,"%sindex.unsort",outdir);
-   sprintf(wdir_tmp2,"%sindex.sort",outdir);
-   strcpy(hbc1,"class=\"header\"");
+   if(LastLog > 0) mklastlog(outdir);
 
-   if(strcmp(Index,"no") == 0) {
+   if(Index == INDEX_NO) {
+      sprintf(wdir,"%sindex.html",outdir);
       if(access(wdir, R_OK) == 0) unlink(wdir);
       return;
    }
 
    if(debug) debuga("%s",text[53]);
 
-   // Root dir
+   // convert any old report hierarchy
    dirp = opendir(outdir);
    while ((direntp = readdir( dirp )) != NULL) {
-      if(strcmp(IndexTree,"date") == 0) {
-         if(!isdigit(direntp->d_name[0]) && !isdigit(direntp->d_name[1])) continue;
-         if(strlen(direntp->d_name) > 4) {
-            bzero(y1,5);
-            bzero(y2,5);
-            bzero(m1,4);
-            bzero(m2,4);
-            bzero(d1,3);
-            bzero(d2,3);
-            if(strcmp(df,"u") == 0) {
-               strncpy(y1,direntp->d_name,4);
-               strncpy(m1,direntp->d_name+4,3);
-               strncpy(d1,direntp->d_name+7,2);
-               strncpy(y2,direntp->d_name+10,4);
-               strncpy(m2,direntp->d_name+14,3);
-               strncpy(d2,direntp->d_name+17,2);
-           } else if(strcmp(df,"e") == 0) {
-               strncpy(y1,direntp->d_name+5,4);
-               strncpy(m1,direntp->d_name+2,3);
-               strncpy(d1,direntp->d_name,2);
-               strncpy(y2,direntp->d_name+15,4);
-               strncpy(m2,direntp->d_name+12,3);
-               strncpy(d2,direntp->d_name+10,2);
-            }
-            conv_month(m1);
-            conv_month(m2);
-         }
-         sprintf(val1,"%s%s",outdir,y1);
-         if(access(val1, R_OK) != 0) mkdir(val1,0755);
-         if(strcmp(m1,m2) != 0) sprintf(val2,"%s/%s-%s",val1,m1,m2);
-         else sprintf(val2,"%s/%s",val1,m1);
-         if(access(val2, R_OK) != 0) mkdir(val2,0755);
-         if(strcmp(d1,d2) != 0) sprintf(val3,"%s/%s-%s",val2,d1,d2);
-         else sprintf(val3,"%s/%s",val2,d1);
-         sprintf(val4,"%s%s",outdir,direntp->d_name);
-         rename(val4,val3);
-         sprintf(val5,"%s/images",val2);
-         if(access(val5, R_OK) != 0) {
-            sprintf(val5,"ln -s \"%simages\" \"%s/images\"",outdir,val2);
-            cstatus=system(val5);
-            if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-               fprintf(stderr, "SARG: command return status %d\n",WEXITSTATUS(cstatus));
-               fprintf(stderr, "SARG: command: %s\n",val5);
-               exit(1);
-            }
+      if(isdigit(direntp->d_name[0]) && isdigit(direntp->d_name[1])) {
+         if(IndexTree == INDEX_TREE_DATE)
+            file_index_to_date_index(direntp->d_name);
+         else
+            date_index_to_file_index(direntp->d_name);
+      }
+   }
+   closedir(dirp);
+
+   if(IndexTree == INDEX_TREE_DATE) {
+      make_date_index();
+   } else {
+      make_file_index();
+   }
+}
+
+static void make_date_index(void)
+{
+   FILE *fp_ou, *fp_ou2, *fp_ou3;
+   DIR *dirp, *dirp2, *dirp3;
+   struct dirent *direntp;
+   struct dirent *direntp2;
+   struct dirent *direntp3;
+   char yearindex[MAXLEN];
+   char yeardir[MAXLEN];
+   char yearnum[10];
+   char monthindex[MAXLEN];
+   char monthdir[MAXLEN];
+   char monthname1[9], monthname2[9];
+   char nmonth[30];
+   char monthnum[10];
+   char dayindex[MAXLEN];
+   char daynum[10];
+   char title[80];
+   int yearsort[150];
+   int nyears;
+   int year;
+   int monthsort[144];
+   int nmonths;
+   int m1, m2, month;
+   int daysort[31*31];
+   int ndays;
+   int d1, d2, day;
+   int i, y, m, d;
+   int order;
+
+   sprintf(yearindex,"%sindex.html",outdir);
+
+   nyears=0;
+   dirp = opendir(outdir);
+   while ((direntp = readdir( dirp )) != NULL) {
+      if(strlen(direntp->d_name) > 4 || !isdigit(direntp->d_name[0]) || !isdigit(direntp->d_name[1]) ||
+         !isdigit(direntp->d_name[2]) || !isdigit(direntp->d_name[3])) continue;
+      year=atoi(direntp->d_name);
+      if (nyears>=sizeof(yearsort)/sizeof(yearsort[0])) {
+         /*
+         If too many years are listed in the directory, we ignore the earliest years. The yearsort array
+         is big enough to accomodate the most ambitious use of sarg but this safety is added to prevent
+         a crash should the directory be polluted by other entries.
+         */
+         if (year>yearsort[0]) {
+            for (i=1 ; i<nyears && year>yearsort[i] ; i++)
+               yearsort[i-1]=yearsort[i];
+            yearsort[i-1]=year;
          }
       } else {
-         if(!isdigit(direntp->d_name[0]) && !isdigit(direntp->d_name[1])) continue;
-         if(strlen(direntp->d_name) == 4) {
-            strcpy(y1,direntp->d_name);
-            sprintf(val1,"%s%s",outdir,direntp->d_name);
-            dirp2 = opendir(val1);
-            while ((direntp2 = readdir( dirp2 )) != NULL) {
-               if(!isdigit(direntp2->d_name[0]) && !isdigit(direntp2->d_name[1])) continue;
-               sprintf(val2,"%s/%s",val1,direntp2->d_name);
-               dirp3 = opendir(val2);
-               while ((direntp3 = readdir( dirp3 )) != NULL) {
-                  if(!isdigit(direntp3->d_name[0]) && !isdigit(direntp3->d_name[1])) continue;
-                  bzero(newname,512);
-                  strcpy(warea,direntp2->d_name);
-                  if((str = strchr(warea,'-')) != 0) {
-                     *str++ = '\0';
-                     strcpy(m1,warea);
-                     strcpy(m2,str);
-                     conv_month_name(m1);
-                     conv_month_name(m2);
-                  } else {
-                     strcpy(m1,warea);
-                     conv_month_name(m1);
-                     strcpy(m2,m1);
-                  }
-                  strcpy(warea,direntp3->d_name);
-                  if((str = strchr(warea,'-')) != 0) {
-                     *str++ = '\0';
-                     strcpy(d1,warea);
-                     strcpy(d2,warea);
-                  } else {
-                     strcpy(d1,warea);
-                     strcpy(d2,warea);
-                  }
-                  if(strcmp(df,"u") == 0) sprintf(val4,"%s%s%s%s-%s%s%s",outdir,y1,m1,d1,y1,m2,d2);
-                  else if(strcmp(df,"e") == 0) sprintf(val4,"%s%s%s%s-%s%s%s",outdir,d1,m1,y1,d2,m2,y1);
-                  sprintf(val5,"%s%s/%s/%s",outdir,y1,direntp2->d_name,direntp3->d_name);
-                  if(rename(val5,val4)) {
-                     fprintf(stderr, "SARG: (index) rename error - %s\n",strerror(errno));
-                     exit(1);
-                  }
-               }
-               (void)rewinddir( dirp3 );
-               (void)closedir( dirp3 );
-            }
-            (void)rewinddir( dirp2 );
-            (void)closedir( dirp2 );
+         for (i=nyears ; i>0 &&  year<yearsort[i-1] ; i--) {
+            yearsort[i]=yearsort[i-1];
          }
-//         sprintf(cmd,"rm -rf %s%s\n",outdir,direntp->d_name);
-//         system(cmd);
+         yearsort[i]=year;
+         nyears++;
       }
    }
-   (void)rewinddir( dirp );
    (void)closedir( dirp );
 
-   if((fp_tmp=fopen(wdir_tmp,"w"))==NULL) {
-      fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir_tmp);
+   order=(strcmp(IndexSortOrder,"A") == 0) ? 1 : -1;
+
+   if((fp_ou=fopen(yearindex,"w"))==NULL) {
+      fprintf(stderr, "SARG: (index) %s: %s - %s\n",text[45],yearindex,strerror(errno));
       exit(1);
    }
-
-   dirp = opendir(outdir);
-   while ((direntp = readdir( dirp )) != NULL) {
-      if(strcmp(IndexTree,"date") == 0) {
-         if(strlen(direntp->d_name) > 4 || (!isdigit(direntp->d_name[0]) && !isdigit(direntp->d_name[1]))) continue;
-         fprintf(fp_tmp,"%s\t%s\n",direntp->d_name,get_size(outdir,direntp->d_name));
-         continue;
-      } else {
-         if(strstr(direntp->d_name,"-") == 0) continue;
-         bzero(newname, 512);
-         if(strcmp(df,"u") == 0) {
-            strncat(newname,direntp->d_name,4);
-            strncpy(month,direntp->d_name+4,3);
+   write_html_header(fp_ou,0,"SARG reports");
+   close_html_header(fp_ou);
+   fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou);
+   fprintf(fp_ou,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",text[130],text[132]);
+   for (y=0 ; y<nyears ; y++) {
+      if (order>0)
+         year=yearsort[y];
+      else
+         year=yearsort[nyears-1-y];
+      sprintf(yearnum,"%04d",year);
+      fprintf(fp_ou,"<tr><td class=\"data2\"><a href=\"%s/index.html\">%s</a></td><td class=\"data2\">%s</td></tr>\n",yearnum,yearnum,get_size(outdir,yearnum));
+      sprintf(yeardir,"%s%s",outdir,yearnum);
+      // Year dir
+      nmonths=0;
+      dirp2 = opendir(yeardir);
+      while ((direntp2 = readdir( dirp2 )) != NULL) {
+         if(!isdigit(direntp2->d_name[0]) || !isdigit(direntp2->d_name[1])) continue;
+         i=-1;
+         if (sscanf(direntp2->d_name,"%d%n",&m1,&i)!=1 || m1<=0 || m1>12 || i<0) continue;
+         if (direntp2->d_name[i]=='-') {
+            if (sscanf(direntp2->d_name+i+1,"%d",&m2)!=1 || m2<m1 || m2>12) continue;
+         } else if (direntp2->d_name[i]!='\0') {
+            continue;
          } else {
-            strncat(newname,direntp->d_name+5,4);
-            strncpy(month,direntp->d_name+2,3);
+            m2=0;
+         }
+         if (nmonths>=sizeof(monthsort)/sizeof(monthsort[0])) {
+            fprintf(stderr,"SARG: Too many month directories in %s\nSupernumerary entries are ignored\n",yeardir);
+            break;
          }
-         month[3]='\0';
-         conv_month(month);
-         strcat(newname,month);
-         if(strcmp(df,"u") == 0) strncat(newname,direntp->d_name+7,2);
-         else strncat(newname,direntp->d_name,2);
-         obtdate(outdir,direntp->d_name,data);
-         obtuser(outdir,direntp->d_name,tuser);
-         obttotal(outdir,direntp->d_name,tbytes,tuser,media);
-         if (sscanf(data,"%d-%d-%d %d:%d:%d %d",&iyear,&imonth,&iday,&ihour,&iminute,&isecond,&idst)==7) {
-            formatdate(data,sizeof(data),iyear,imonth,iday,ihour,iminute,isecond,idst);
-            fprintf(fp_tmp,"%04d%02d%02d%02d%02d%02d;%s;%s;%s;%s;%s;%s\n",iyear,imonth,iday,ihour,iminute,isecond, direntp->d_name, data, tuser, tbytes, media,newname);
+         month=m1*16+m2;
+         for (i=nmonths ; i>0 &&  month<monthsort[i-1] ; i--) {
+            monthsort[i]=monthsort[i-1];
+         }
+         monthsort[i]=month;
+         nmonths++;
+      }
+      (void)closedir(dirp2);
+      sprintf(monthindex,"%s/index.html",yeardir);
+      if((fp_ou2=fopen(monthindex,"w"))==NULL) {
+         fprintf(stderr, "SARG: (index) %s: %s - %s\n",text[45],monthindex,strerror(errno));
+         exit(1);
+      }
+      snprintf(title,sizeof(title),"SARG: report for %04d",year);
+      write_html_header(fp_ou2,1,title);
+      close_html_header(fp_ou2);
+      fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou2);
+      fprintf(fp_ou2,"<tr><th class=\"header_l\">%s/%s</th></tr>\n",text[130],text[131]);
+      for (m=0 ; m<nmonths ; m++) {
+         if (order>0)
+            month=monthsort[m];
+         else
+            month=monthsort[nmonths-1-m];
+         m1=month / 16;
+         if(month % 16 != 0) {
+            m2=month % 16;
+            sprintf(monthnum,"%02d-%02d",m1,m2);
+            sprintf(monthname1,"%02d",m1);
+            sprintf(monthname2,"%02d",m2);
+            name_month(monthname1,sizeof(monthname1));
+            name_month(monthname2,sizeof(monthname2));
+            sprintf(nmonth,"%s-%s",monthname1,monthname2);
          } else {
-            /*
-            Old code to parse a date stored by sarg before 2.2.6.1 in the sarg-date file of each report directory.
-            */
-            getword_start(&gwarea,data);
-            if (getword_multisep(mon,sizeof(mon),&gwarea,' ')<0) {
-               printf("SARG: Maybe you have a broken week day in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-               exit(1);
-            }
-            if (getword_multisep(mon,sizeof(mon),&gwarea,' ')<0) {
-               printf("SARG: Maybe you have a broken month in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-               exit(1);
+            sprintf(nmonth,"%02d",m1);
+            sprintf(monthnum,"%02d",m1);
+            name_month(nmonth,sizeof(nmonth));
+         }
+         fprintf(fp_ou2,"<tr><td class=\"data2\"><a href=\"%s/index.html\">%s %s</a></td></tr>\n",monthnum,yearnum,nmonth);
+
+         sprintf(monthdir,"%s/%s",yeardir,monthnum);
+         // month dir
+         ndays=0;
+         dirp3 = opendir(monthdir);
+         while ((direntp3 = readdir( dirp3 )) != NULL) {
+            if(!isdigit(direntp3->d_name[0]) && !isdigit(direntp3->d_name[1])) continue;
+            i=-1;
+            if (sscanf(direntp3->d_name,"%d%n",&d1,&i)!=1 || d1<=0 || d1>31 || i<0) continue;
+            if (direntp3->d_name[i]=='-') {
+               if (sscanf(direntp3->d_name+i+1,"%d",&d2)!=1 || d2<d1 || d2>31) continue;
+            } else if (direntp3->d_name[i]!='\0') {
+               continue;
+            } else {
+               d2=0;
             }
-            if (getword_multisep(day,sizeof(day),&gwarea,' ')<0) {
-               printf("SARG: Maybe you have a broken day in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-               exit(1);
+            if (ndays>=sizeof(daysort)/sizeof(daysort[0])) {
+               fprintf(stderr,"SARG: Too many day directories in %s\nSupernumerary entries are ignored\n",monthdir);
+               break;
             }
-            if (getword_multisep(hour,sizeof(hour),&gwarea,' ')<0) {
-               printf("SARG: Maybe you have a broken time in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-               exit(1);
+            day=d1*32+d2;
+            for (i=ndays ; i>0 &&  day<daysort[i-1] ; i--) {
+               daysort[i]=daysort[i-1];
             }
-            do {
-               if (getword_multisep(year,sizeof(year),&gwarea,' ')<0) {
-                  printf("SARG: Maybe you have a broken year in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-                  exit(1);
-               }
-            } while (year[0] && !isdigit(year[0])); //skip time zone information with spaces until the year is found
-            strcpy(html,hour);
-            if (sscanf(hour,"%d:%d:%d",&ihour,&iminute,&isecond)!=3) {
-               printf("SARG: Maybe you have a broken time in your %s%s/sarg-date file.\n",outdir,direntp->d_name);
-               exit(1);
+            daysort[i]=day;
+            ndays++;
+         }
+         (void)closedir(dirp3);
+         sprintf(dayindex,"%s/index.html",monthdir);
+         if((fp_ou3=fopen(dayindex,"w"))==NULL) {
+            fprintf(stderr, "SARG: (index) %s: %s - %s\n",text[45],dayindex,strerror(errno));
+            exit(1);
+         }
+         snprintf(title,sizeof(title),"SARG: report for %04d/%02d",year,month);
+         write_html_header(fp_ou3,2,title);
+         close_html_header(fp_ou3);
+         fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou3);
+         fprintf(fp_ou3,"<tr><th class=\"header_l\">%s/%s/%s</th></tr>\n",text[130],text[131],text[127]);
+         for (d=0 ; d<ndays ; d++) {
+            if (order>0)
+               day=daysort[d];
+            else
+               day=daysort[ndays-1-d];
+            d1=day / 32;
+            if(day % 32 != 0) {
+               d2=day % 32;
+               sprintf(daynum,"%02d-%02d",d1,d2);
+            } else {
+               sprintf(daynum,"%02d",d1);
             }
-            buildymd(day,mon,year,ftime);
-            fprintf(fp_tmp,"%s%02d%02d%02d;%s;%s;%s;%s;%s;%s\n",ftime, ihour, iminute, isecond, direntp->d_name, data, tuser, tbytes, media,newname);
+            fprintf(fp_ou3,"<tr><td class=\"data2\"><a href=\"%s/index.html\">%s %s %s</a></td></tr>\n",daynum,yearnum,nmonth,daynum);
          }
-         continue;
+         fputs("</table></div>\n",fp_ou3);
+         write_html_trailer(fp_ou3);
+         fclose(fp_ou3);
       }
+      fputs("</table></div>\n",fp_ou2);
+      write_html_trailer(fp_ou2);
+      fclose(fp_ou2);
    }
 
-   if(fp_tmp) fclose(fp_tmp);
-   if(strcmp(IndexTree,"file") == 0) {
-      (void)rewinddir( dirp );
-      (void)closedir( dirp );
-   }
+   fputs("</table></div>\n",fp_ou);
+   write_html_trailer(fp_ou);
+   fclose(fp_ou);
+}
 
-   if(strcmp(IndexTree,"date") == 0) {
-      if(strcmp(IndexSortOrder,"A") == 0) sprintf(warea,"sort -k 1,1 \"%s\" -o \"%s\"", wdir_tmp, wdir_tmp2);
-      else sprintf(warea,"sort -r -k 1,1 \"%s\" -o \"%s\"", wdir_tmp, wdir_tmp2);
-      cstatus=system(warea);
-      if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-         fprintf(stderr, "SARG: sort command return status %d\n",WEXITSTATUS(cstatus));
-         fprintf(stderr, "SARG: sort command: %s\n",warea);
-         exit(1);
-      }
-      if((fp_tmp=fopen(wdir_tmp2,"r"))==NULL) {
-         fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir_tmp2);
-         fprintf(stderr, "SARG: sort command: %s\n",warea);
+static void make_file_index(void)
+{
+   #define MAX_CREATION_DATE 15
+   #define MAX_DIR_NAME 30
+   FILE *fp_ou;
+   DIR *dirp;
+   struct dirent *direntp;
+   char wdir[MAXLEN];
+   char month[4];
+   char data[80];
+   char tuser[20];
+   char tbytes[20];
+   char media[20];
+   char ftime[128];
+   char day[6], mon[8], year[40], hour[10];
+   int iyear, imonth, iday, ihour, iminute, isecond, idst;
+   int nsort;
+   int nallocated;
+   int order;
+   int i;
+   int cmp;
+   struct getwordstruct gwarea;
+   struct sortstruct
+   {
+      char sortname[9];
+      char creationdate[MAX_CREATION_DATE];
+      char dirname[MAX_DIR_NAME];
+      char date[60];
+   } **sortlist, *item, **tempsort;
+
+   sprintf(wdir,"%sindex.html",outdir);
+
+   order=(strcmp(IndexSortOrder,"A") == 0) ? 1 : -1;
+
+   dirp = opendir(outdir);
+
+   nsort=0;
+   nallocated=0;
+   sortlist=NULL;
+   while ((direntp = readdir( dirp )) != NULL) {
+      if (strchr(direntp->d_name,'-') == 0) continue;
+      if (strlen(direntp->d_name)>MAX_DIR_NAME) continue;
+      item=malloc(sizeof(*item));
+      if (!item) {
+         fprintf(stderr,"SARG: not enough memory to sort the index\n");
          exit(1);
       }
-      unlink(wdir_tmp);
-      if((fp_ou=fopen(wdir,"w"))==NULL) {
-         fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir);
-         exit(1);
+      if(strcmp(df,"u") == 0) {
+         strncpy(item->sortname,direntp->d_name,4);
+         strncpy(month,direntp->d_name+4,3);
+      } else {
+         strncpy(item->sortname,direntp->d_name+5,4);
+         strncpy(month,direntp->d_name+2,3);
       }
-      write_html_header(fp_ou, ".");
-      fprintf(fp_ou,"<tr><th %s>%s</th><th %s>%s</th></tr>\n",hbc1,text[130],hbc1,text[132]);
-      while(fgets(wwork1,sizeof(wwork1),fp_tmp)!=NULL) {
-         getword_start(&gwarea,wwork1);
-         if (getword(tmp4,sizeof(tmp4),&gwarea,'\t')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
+      item->sortname[4]='\0';
+      month[3]='\0';
+      conv_month(month);
+      strcat(item->sortname,month);
+      if(strcmp(df,"u") == 0) strncat(item->sortname,direntp->d_name+7,2);
+      else strncat(item->sortname,direntp->d_name,2);
+      obtdate(outdir,direntp->d_name,data);
+      if (sscanf(data,"%d-%d-%d %d:%d:%d %d",&iyear,&imonth,&iday,&ihour,&iminute,&isecond,&idst)==7) {
+         formatdate(data,sizeof(data),iyear,imonth,iday,ihour,iminute,isecond,idst);
+         snprintf(item->creationdate,sizeof(item->creationdate),"%04d%02d%02d%02d%02d%02d",iyear,imonth,iday,ihour,iminute,isecond);
+      } else {
+         /*
+         Old code to parse a date stored by sarg before 2.2.6.1 in the sarg-date file of each report directory.
+         */
+         getword_start(&gwarea,data);
+         if (getword_skip(16,&gwarea,' ')<0) {
+            debuga(_("Maybe you have a broken week day in your %s%s/sarg-date file"),outdir,direntp->d_name);
             exit(1);
          }
-         fprintf(fp_ou,"<tr><td class=\"data2\"><a href=\"%s\">%s</a></td><td class=\"data2\">%s</td></tr>\n",tmp4,tmp4,gwarea.current);
-         sprintf(tmp2,"%s%s",outdir,tmp4);
-         sprintf(tmp3,"%s%s/index.unsort",outdir,tmp4);
-         // Year dir
-         if((fp_ou2=fopen(tmp3,"w"))==NULL) {
-            fprintf(stderr, "SARG: (index) %s: %s\n",text[45],tmp3);
+         if (getword_multisep(mon,sizeof(mon),&gwarea,' ')<0) {
+            debuga(_("Maybe you have a broken month in your %s%s/sarg-date file"),outdir,direntp->d_name);
             exit(1);
          }
-         dirp2 = opendir(tmp2);
-         while ((direntp2 = readdir( dirp2 )) != NULL) {
-            if(!isdigit(direntp2->d_name[0]) && !isdigit(direntp2->d_name[1])) continue;
-            fprintf(fp_ou2,"%s\n",direntp2->d_name);
+         if (getword_multisep(day,sizeof(day),&gwarea,' ')<0) {
+            debuga(_("Maybe you have a broken day in your %s%s/sarg-date file"),outdir,direntp->d_name);
+            exit(1);
          }
-         if(fp_ou2) fclose(fp_ou2);
-         (void)rewinddir(dirp2);
-         (void)closedir(dirp2);
-         sprintf(wdir_tmp3,"%s%s/index.sort",outdir,tmp4);
-         if(strcmp(IndexSortOrder,"A") == 0) sprintf(csort,"sort -n \"%s\" -o \"%s\"", tmp3, wdir_tmp3);
-         else sprintf(csort,"sort -n -r \"%s\" -o \"%s\"", tmp3, wdir_tmp3);
-         cstatus=system(csort);
-         if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-            fprintf(stderr, "SARG: sort command return status %d\n",WEXITSTATUS(cstatus));
-            fprintf(stderr, "SARG: sort command: %s\n",csort);
+         if (getword_multisep(hour,sizeof(hour),&gwarea,' ')<0) {
+            debuga(_("Maybe you have a broken time in your %s%s/sarg-date file"),outdir,direntp->d_name);
             exit(1);
          }
-         unlink(tmp3);
-         if((fp_tmp2=fopen(wdir_tmp3,"r"))==NULL) {
-            fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir_tmp3);
+         do {
+            if (getword_multisep(year,sizeof(year),&gwarea,' ')<0) {
+               debuga(_("Maybe you have a broken year in your %s%s/sarg-date file"),outdir,direntp->d_name);
+               exit(1);
+            }
+         } while (year[0] && !isdigit(year[0])); //skip time zone information with spaces until the year is found
+         if (sscanf(hour,"%d:%d:%d",&ihour,&iminute,&isecond)!=3) {
+            debuga(_("Maybe you have a broken time in your %s%s/sarg-date file"),outdir,direntp->d_name);
             exit(1);
          }
-         sprintf(tmp3,"%s%s/index.html",outdir,tmp4);
-         if((fp_ou2=fopen(tmp3,"w"))==NULL) {
-            fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir);
+         buildymd(day,mon,year,ftime);
+         snprintf(item->creationdate,sizeof(item->creationdate),"%s%02d%02d%02d",ftime, ihour, iminute, isecond);
+      }
+      strcpy(item->dirname,direntp->d_name);
+      strncpy(item->date,data,sizeof(item->date));
+      if (nsort+1>nallocated) {
+         nallocated+=10;
+         tempsort=realloc(sortlist,nallocated*sizeof(*item));
+         if (!tempsort) {
+            fprintf(stderr,"SARG: not enough memory to sort the index\n");
             exit(1);
          }
-         write_html_header(fp_ou2,"..");
-         fprintf(fp_ou2,"<tr><th %s>%s/%s</th></tr>\n",hbc1,text[130],text[131]);
-         while(fgets(wwork1,sizeof(wwork1),fp_tmp2)!=NULL) {
-            fixendofline(wwork1);
-            strcpy(tmp5,wwork1);
-            if((str = strchr(tmp5,'-')) != 0) {
-               *str++ = '\0';
-               strcpy(tmp6,str);
-               name_month(tmp5,sizeof(tmp5));
-               name_month(tmp6,sizeof(tmp6));
-               sprintf(nmonth,"%s-%s",tmp5,tmp6);
-            } else {
-               strcpy(nmonth,tmp5);
-               name_month(nmonth,sizeof(nmonth));
-            }
-            fprintf(fp_ou2,"<tr><td class=\"data2\"><a href=\"%s\">%s %s</a></td></tr>\n",wwork1,tmp4,nmonth);
-
-            sprintf(val1,"%s%s/%s",outdir,tmp4,wwork1);
-            sprintf(tmp5,"%s%s/%s/index.unsort",outdir,tmp4,wwork1);
-            if((fp_ou3=fopen(tmp5,"w"))==NULL) {
-               fprintf(stderr, "SARG: (index) %s: %s\n",text[45],tmp5);
-               exit(1);
-            }
-            // month dir
-            dirp3 = opendir(val1);
-            while ((direntp3 = readdir( dirp3 )) != NULL) {
-               if(!isdigit(direntp3->d_name[0]) && !isdigit(direntp3->d_name[1])) continue;
-               fprintf(fp_ou3,"%s\n",direntp3->d_name);
-            }
-            if(fp_ou3) fclose(fp_ou3);
-            (void)rewinddir(dirp3);
-            (void)closedir(dirp3);
-            unlink(wdir_tmp3);
-            sprintf(tmp6,"%s%s/%s/index.sort",outdir,tmp4,wwork1);
-            if(strcmp(IndexSortOrder,"A") == 0) sprintf(csort,"sort -n \"%s\" -o \"%s\"", tmp5, tmp6);
-            else sprintf(csort,"sort -n -r \"%s\" -o \"%s\"", tmp5, tmp6);
-            cstatus=system(csort);
-            if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-               fprintf(stderr, "SARG: sort command return status %d\n",WEXITSTATUS(cstatus));
-               fprintf(stderr, "SARG: sort command: %s\n",csort);
-               exit(1);
-            }
-            unlink(tmp5);
-            sprintf(val2,"%s%s/%s/index.html",outdir,tmp4,wwork1);
-            sprintf(val3,"%s/%s",tmp4,wwork1);
-            unlink(val2);
-            if((fp_ou3=fopen(val2,"w"))==NULL) {
-               fprintf(stderr, "SARG: (index) %s: %s\n",text[45],val2);
-               exit(1);
-            }
-            if((fp_tmp3=fopen(tmp6,"r"))==NULL) {
-               fprintf(stderr, "SARG: (index) %s: %s\n",text[45],tmp6);
-               exit(1);
-            }
-            write_html_header(fp_ou3,"../..");
-            fprintf(fp_ou3,"<tr><th %s>%s/%s/%s</th></tr>\n",hbc1,text[130],text[131],text[127]);
-            while(fgets(warea,MAXLEN,fp_tmp3)!=NULL) {
-               warea[strlen(warea)-1]='\0';
-               fprintf(fp_ou3,"<tr><td class=\"data2\"><a href=\"%s\">%s %s %s</a></td></tr>\n",warea,tmp4,nmonth,warea);
-            }
-            if(fp_tmp3) fclose(fp_tmp3);
-            write_html_trailer(fp_ou3);
-            if(fp_ou3) fclose(fp_ou3);
-            unlink(tmp6);
+         sortlist=tempsort;
+      }
+      for (i=nsort ; i>0 ; i--) {
+         cmp=strcmp(item->sortname,sortlist[i-1]->sortname);
+         if (cmp==0) cmp=strcmp(item->creationdate,sortlist[i-1]->creationdate);
+         if (cmp>=0) {
+            break;
          }
-         write_html_trailer(fp_ou2);
-         if(fp_ou2) fclose(fp_ou2);
+         sortlist[i]=sortlist[i-1];
       }
-      (void)rewinddir(dirp);
-      (void)closedir(dirp);
-      if(fp_tmp) fclose(fp_tmp);
-      unlink(tmp6);
-      unlink(wdir_tmp2);
-   } else {
-      if(strcmp(IndexSortOrder,"A") == 0) sprintf(warea,"sort -t\";\" -k 7,7 -k 1,1 \"%s\" -o \"%s\"", wdir_tmp, wdir_tmp2);
-      else sprintf(warea,"sort -r -t\";\" -k 7,7 -k 1,1 \"%s\" -o \"%s\"", wdir_tmp, wdir_tmp2);
-      cstatus=system(warea);
-      if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-         fprintf(stderr, "SARG: sort command return status %d\n",WEXITSTATUS(cstatus));
-         fprintf(stderr, "SARG: sort command: %s\n",warea);
+      sortlist[i]=item;
+      nsort++;
+   }
+
+   (void)closedir( dirp );
+
+   if((fp_ou=fopen(wdir,"w"))==NULL) {
+      fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir);
+      exit(1);
+   }
+   write_html_header(fp_ou,0,"SARG reports");
+   close_html_header(fp_ou);
+   fputs("<div class=\"index\"><table cellpadding=\"1\" cellspacing=\"2\">\n<tr><td></td><td></td></tr>\n",fp_ou);
+   fprintf(fp_ou,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",text[101],text[102],text[103],text[93],text[96]);
+   for (i=0 ; i<nsort ; i++) {
+      if (order>0)
+         item=sortlist[i];
+      else
+         item=sortlist[nsort-i-1];
+      obtuser(outdir,item->dirname,tuser);
+      obttotal(outdir,item->dirname,tbytes,tuser,media);
+      fprintf(fp_ou,"<tr><td class=\"data2\"><a href='%s/%s'>%s</a></td><td class=\"data2\">%s</td><td class=\"data\">%s</td><td class=\"data\">%s</td><td class=\"data\">%s</td></tr>\n",item->dirname,ReplaceIndex,item->dirname,item->date,tuser,tbytes,media);
+   }
+   fputs("</table></div>\n",fp_ou);
+   write_html_trailer(fp_ou);
+   fclose(fp_ou);
+
+   if (sortlist) {
+      for (i=0 ; i<nsort ; i++)
+         free(sortlist[i]);
+      free(sortlist);
+   }
+}
+
+static void file_index_to_date_index(const char *entry)
+{
+   int y1, y2, d1, d2;
+   int i, j;
+   int ndirlen;
+   int monthlen;
+   char m1[8], m2[8];
+   char olddir[MAXLEN], newdir[MAXLEN];
+
+   if(strlen(entry) < 19) return;
+
+   y1=0;
+   y2=0;
+   memset(m1,0,sizeof(m1));
+   memset(m2,0,sizeof(m2));
+   d1=0;
+   d2=0;
+   i=0;
+   if(strcmp(df,"u") == 0) {
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         y1=y1*10+(entry[i++]-'0');
+      if (j!=4) return;
+      for (j=0 ; j<sizeof(m1)-1 && entry[i] && isalpha(entry[i]) ; j++)
+         m1[j]=entry[i++];
+      if (j!=3) return;
+      m1[j]='\0';
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         d1=d1*10+(entry[i++]-'0');
+      if (j!=2) return;
+
+      if (entry[i++]!='-') return;
+
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         y2=y2*10+(entry[i++]-'0');
+      if (j!=4) return;
+      for (j=0 ; j<sizeof(m2)-1 && entry[i] && isalpha(entry[i]) ; j++)
+         m2[j]=entry[i++];
+      if (j!=3) return;
+      m2[j]='\0';
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         d2=d2*10+(entry[i++]-'0');
+      if (j!=2) return;
+   } else if(strcmp(df,"e") == 0) {
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         d1=d1*10+(entry[i++]-'0');
+      if (j!=2) return;
+      for (j=0 ; j<sizeof(m1)-1 && entry[i] && isalpha(entry[i]) ; j++)
+         m1[j]=entry[i++];
+      if (j!=3) return;
+      m1[j]='\0';
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         y1=y1*10+(entry[i++]-'0');
+      if (j!=4) return;
+
+      if (entry[i++]!='-') return;
+
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         d2=d2*10+(entry[i++]-'0');
+      if (j!=2) return;
+      for (j=0 ; j<sizeof(m2)-1 && entry[i] && isalpha(entry[i]) ; j++)
+         m2[j]=entry[i++];
+      if (j!=3) return;
+      m2[j]='\0';
+      for (j=0 ; entry[i] && isdigit(entry[i]) ; j++)
+         y2=y2*10+(entry[i++]-'0');
+      if (j!=4) return;
+   } else
+      return;
+
+   conv_month(m1);
+   conv_month(m2);
+   ndirlen=sprintf(newdir,"%s%04d",outdir,y1);
+   if(access(newdir, R_OK) != 0) mkdir(newdir,0755);
+   if(strcmp(m1,m2) != 0) ndirlen+=sprintf(newdir+ndirlen,"/%s-%s",m1,m2);
+   else ndirlen+=sprintf(newdir+ndirlen,"/%s",m1);
+   if(access(newdir, R_OK) != 0) mkdir(newdir,0755);
+   monthlen=ndirlen;
+   if(d1!=d2) ndirlen+=sprintf(newdir+ndirlen,"/%02d-%02d",d1,d2);
+   else ndirlen+=sprintf(newdir+ndirlen,"/%02d",d1);
+
+   sprintf(olddir,"%s%s",outdir,entry);
+   if (rename(olddir,newdir)) {
+      fprintf(stderr, "SARG: (index) rename error from \"%s\" to \"%s\" - %s\n",olddir,newdir,strerror(errno));
+      exit(1);
+   }
+
+   strcpy(newdir+monthlen,"/images");
+   if(access(newdir, R_OK) != 0) {
+#ifdef HAVE_SYMLINK
+      char linkdir[MAXLEN];
+
+      sprintf(linkdir,"%simages",outdir);
+      if (symlink(linkdir,newdir)) {
+         fprintf(stderr, "SARG: failed to create link \"%s\" to \"%s\" - %s\n",linkdir,newdir,strerror(errno));
          exit(1);
       }
-      if((fp_tmp2=fopen(wdir_tmp2,"r"))==NULL) {
-         fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir_tmp2);
-         fprintf(stderr, "SARG: sort command: %s\n",warea);
+#else
+      char cmd[MAXLEN];
+      int cstatus;
+
+      sprintf(cmd,"ln -s \"%simages\" \"%s/images\"",outdir,newdir);
+      cstatus=system(cmd);
+      if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
+         fprintf(stderr, "SARG: command return status %d\n",WEXITSTATUS(cstatus));
+         fprintf(stderr, "SARG: command: %s\n",cmd);
          exit(1);
       }
-      unlink(wdir_tmp);
-      if((fp_ou=fopen(wdir,"w"))==NULL) {
-         fprintf(stderr, "SARG: (index) %s: %s\n",text[45],wdir);
-         exit(1);
+#endif
+   }
+}
+
+static void date_index_to_file_index(const char *entry)
+{
+   int y1, next;
+   int val1len;
+   int d1, d2;
+   int i, j;
+   char val1[MAXLEN];
+   char m1[8], m2[8];
+   char *str;
+   char newdir[MAXLEN], olddir[MAXLEN];
+   DIR *dirp2, *dirp3;
+   struct dirent *direntp2;
+   struct dirent *direntp3;
+
+   if(strlen(entry) != 4) return;
+
+   next=-1;
+   if (sscanf(entry,"%d%n",&y1,&next)!=1 || next<0 || entry[next]) return;
+
+   val1len=sprintf(val1,"%s%s",outdir,entry);
+   dirp2 = opendir(val1);
+   if (!dirp2) return;
+   while ((direntp2 = readdir( dirp2 )) != NULL) {
+      if(!isdigit(direntp2->d_name[0]) || !isdigit(direntp2->d_name[1])) continue;
+      i=0;
+      str=direntp2->d_name;
+      for (j=0 ; j<sizeof(m1) && str[i] && isdigit(str[i]) ; j++)
+         m1[j]=str[i++];
+      if (j>=sizeof(m1)) continue;
+      m1[j]='\0';
+      conv_month_name(m1);
+      if (str[i]=='-') {
+         i++;
+         for (j=0 ; j<sizeof(m2) && str[i] && isdigit(str[i]) ; j++)
+            m2[j]=str[i++];
+         if (j>=sizeof(m2)) continue;
+         m2[j]='\0';
+         conv_month_name(m2);
+      } else if (!str[i]) {
+         strcpy(m2,m1);
+      } else {
+         continue;
       }
-      write_html_header(fp_ou,".");
-      fprintf(fp_ou,"<tr><th %s>%s</th><th %s>%s</th><th %s>%s</th><th %s>%s</th><th %s>%s</th></tr>\n",hbc1,text[101],hbc1,text[102],hbc1,text[103],hbc1,text[93],hbc1,text[96]);
-      while(fgets(buf,sizeof(buf),fp_tmp2)!=NULL) {
-         getword_start(&gwarea,buf);
-         if (getword_multisep(period,sizeof(period),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
-            exit(1);
-         }
-         if (getword_multisep(period,sizeof(period),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
-            exit(1);
-         }
-         if (getword_multisep(data,sizeof(data),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
-            exit(1);
-         }
-         if (getword_multisep(tuser,sizeof(tuser),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
-            exit(1);
-         }
-         if (getword_multisep(tbytes,sizeof(tbytes),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
-            exit(1);
+
+      sprintf(val1+val1len,"/%s",direntp2->d_name);
+      dirp3 = opendir(val1);
+      if (!dirp3) continue;
+      while ((direntp3 = readdir( dirp3 )) != NULL) {
+         if(!isdigit(direntp3->d_name[0]) || !isdigit(direntp3->d_name[1])) continue;
+         i=0;
+         str=direntp3->d_name;
+         d1=0;
+         for (j=0 ; str[i] && isdigit(str[i]) ; j++)
+            d1=d1*10+(str[i++]-'0');
+         if (j!=2) continue;
+         if (str[i]=='-') {
+            i++;
+            d2=0;
+            for (j=0 ; str[i] && isdigit(str[i]) ; j++)
+               d2=d2*10+(str[i++]-'0');
+            if (j!=2) continue;
+         } else if (!str[i]) {
+            d2=d1;
+         } else {
+            continue;
          }
-         if (getword_multisep(media,sizeof(media),&gwarea,';')<0) {
-            printf("SARG: Maybe you have a broken record or garbage in your %s file.\n",wdir_tmp2);
+
+         if(strcmp(df,"u") == 0) sprintf(newdir,"%s%04d%s%02d-%04d%s%02d",outdir,y1,m1,d1,y1,m2,d2);
+         else if(strcmp(df,"e") == 0) sprintf(newdir,"%s%02d%s%04d-%02d%s%04d",outdir,d1,m1,y1,d2,m2,y1);
+         else continue;
+         sprintf(olddir,"%s%04d/%s/%s",outdir,y1,direntp2->d_name,direntp3->d_name);
+         if(rename(olddir,newdir)) {
+            fprintf(stderr, "SARG: (index) rename error from \"%s\" to \"%s\" - %s\n",olddir,newdir,strerror(errno));
             exit(1);
          }
-         fprintf(fp_ou,"<tr><td class=\"data2\"><a href='%s/%s'>%s</a></td><td class=\"data2\">%s</td><td class=\"data\">%s</td><td class=\"data\">%s</td><td class=\"data\">%s</td></tr>\n",period,ReplaceIndex,period,data,tuser,tbytes,media);
       }
-      if(fp_tmp2) fclose(fp_tmp2);
-      unlink(wdir_tmp2);
+      (void)closedir( dirp3 );
    }
+   (void)closedir( dirp2 );
 
-   write_html_trailer(fp_ou);
-   if(fp_ou) fclose(fp_ou);
+   /*!
+   \bug The links to the images in the reports are broken after moving the directories
+   as the the HTML files are not at the right level for the images any more.
+   */
 }
+