"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/topuser.c" (24 Dec 2019, 26983 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "topuser.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    9  * ---------------------------------------------------------------------
   10  *
   11  *  This program is free software; you can redistribute it and/or modify
   12  *  it under the terms of the GNU General Public License as published by
   13  *  the Free Software Foundation; either version 2 of the License, or
   14  *  (at your option) any later version.
   15  *
   16  *  This program is distributed in the hope that it will be useful,
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  *  GNU General Public License for more details.
   20  *
   21  *  You should have received a copy of the GNU General Public License
   22  *  along with this program; if not, write to the Free Software
   23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   24  *
   25  */
   26 
   27 #include "include/conf.h"
   28 #include "include/defs.h"
   29 #include "include/filelist.h"
   30 
   31 struct TopUserStatistics
   32 {
   33     long long int ttnbytes;
   34     long long int ttnacc;
   35     long long int ttnelap;
   36     long long int ttnincache;
   37     long long int ttnoucache;
   38     int totuser;
   39 };
   40 
   41 struct SortInfoStruct
   42 {
   43     const char *sort_field;
   44     const char *sort_order;
   45 };
   46 
   47 extern struct globalstatstruct globstat;
   48 extern bool smartfilter;
   49 
   50 /*!
   51 Save the total number of users. The number is written in sarg-users and set
   52 in a global variable for further reference.
   53 
   54 \param totuser The total number of users.
   55 */
   56 static void set_total_users(int totuser)
   57 {
   58     char tusr[1024];
   59     FILE *fp_ou;
   60 
   61     format_path(__FILE__, __LINE__, tusr, sizeof(tusr), "%s/sarg-users", outdirname);
   62     if ((fp_ou=fopen(tusr,"w"))==NULL) {
   63         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tusr,strerror(errno));
   64         exit(EXIT_FAILURE);
   65     }
   66     fprintf(fp_ou,"%d\n",totuser);
   67     if (fclose(fp_ou)==EOF) {
   68         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),tusr,strerror(errno));
   69         exit(EXIT_FAILURE);
   70     }
   71     globstat.totuser=totuser;
   72 }
   73 
   74 /*!
   75  * Generate a HTML report with the users downloading the most.
   76  *
   77  * \param ListFile Name of the file with the sorted list of users.
   78  * \param Statis Statistics about the data collected from the log file.
   79  * \param SortInfo Strings explaining how the list was sorted.
   80  */
   81 static void TopUser_HtmlReport(const char *ListFile,struct TopUserStatistics *Statis,struct SortInfoStruct *SortInfo)
   82 {
   83     FileObject *fp_top1 = NULL;
   84     FILE *fp_top3 = NULL;
   85     long long int nbytes;
   86     long long int nacc;
   87     long long int elap, incac, oucac;
   88     double perc=0.00;
   89     double perc2=0.00;
   90     double inperc=0.00, ouperc=0.00;
   91     int posicao=0;
   92     char top3[MAXLEN];
   93     char user[MAX_USER_LEN];
   94     char title[80];
   95     char *warea;
   96     bool ntopuser=false;
   97     int topcount=0;
   98     struct getwordstruct gwarea;
   99     longline line;
  100     struct userinfostruct *uinfo;
  101 
  102     if ((fp_top1=FileObject_Open(ListFile))==NULL) {
  103         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ListFile,FileObject_GetLastOpenError());
  104         exit(EXIT_FAILURE);
  105     }
  106 
  107     format_path(__FILE__, __LINE__, top3, sizeof(top3), "%s/"INDEX_HTML_FILE, outdirname);
  108     if ((fp_top3=fopen(top3,"w"))==NULL) {
  109         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),top3,strerror(errno));
  110         exit(EXIT_FAILURE);
  111     }
  112 
  113     snprintf(title,sizeof(title),_("SARG report for %s"),period.text);
  114     write_html_header(fp_top3,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,title,HTML_JS_SORTTABLE);
  115     fputs("<tr><td class=\"header_c\">",fp_top3);
  116     fprintf(fp_top3,_("Period: %s"),period.html);
  117     fputs("</td></tr>\n",fp_top3);
  118     if ((ReportType & REPORT_TYPE_TOPUSERS) != 0) {
  119         fputs("<tr><td class=\"header_c\">",fp_top3);
  120         fprintf(fp_top3,_("Sort: %s, %s"),SortInfo->sort_field,SortInfo->sort_order);
  121         fputs("</td></tr>\n",fp_top3);
  122         fprintf(fp_top3,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Top users"));
  123     } else {
  124         /* TRANSLATORS: This is the title of the main report page when no
  125          * top users list are requested.
  126          */
  127         fprintf(fp_top3,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Table of content"));
  128     }
  129     close_html_header(fp_top3);
  130 
  131     if (!indexonly) {
  132         fputs("<div class=\"report\"><table cellpadding=\"1\" cellspacing=\"2\">\n",fp_top3);
  133         if ((ReportType & REPORT_TYPE_TOPSITES) != 0 && !Privacy) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"topsites.html\">%s</a></td></tr>\n",_("Top sites"));
  134         if ((ReportType & REPORT_TYPE_SITES_USERS) != 0 && !Privacy) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"siteuser.html\">%s</a></td></tr>\n",_("Sites & Users"));
  135         if (dansguardian_count) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"dansguardian.html\">%s</a></td></tr>\n",_("DansGuardian"));
  136         if (redirector_count) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"redirector.html\">%s</a></td></tr>\n",_("Redirector"));
  137         if (is_download()) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"download.html\">%s</a></td></tr>\n",_("Downloads"));
  138         if (is_denied()) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"denied.html\">%s</a></td></tr>\n",_("Denied accesses"));
  139         if (is_authfail()) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"authfail.html\">%s</a></td></tr>\n",_("Authentication Failures"));
  140         if (smartfilter) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"smartfilter.html\">%s</a></td></tr>\n",_("SmartFilter"));
  141         if (useragent_count) fprintf(fp_top3,"<tr><td class=\"link\" colspan=\"0\"><a href=\"useragent.html\">%s</a></td></tr>\n",_("Useragent"));
  142         fputs("<tr><td></td></tr>\n</table></div>\n",fp_top3);
  143     }
  144 
  145     if ((ReportType & REPORT_TYPE_TOPUSERS) == 0) {
  146         fputs("</body>\n</html>\n",fp_top3);
  147         if (fclose (fp_top3)==EOF) {
  148             debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),top3,strerror(errno));
  149             exit(EXIT_FAILURE);
  150         }
  151         if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("No top users report because it is not configured in report_type\n"));
  152         return;
  153     }
  154 
  155     fputs("<div class=\"report\"><table cellpadding=\"1\" cellspacing=\"2\"",fp_top3);
  156     if (SortTableJs[0])
  157         fputs(" class=\"sortable\"",fp_top3);
  158     fputs(">\n<thead><tr>",fp_top3);
  159 
  160     if ((TopUserFields & TOPUSERFIELDS_NUM) != 0)
  161         fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("NUM"));
  162     if ((TopUserFields & TOPUSERFIELDS_DATE_TIME) !=0 && (ReportType & REPORT_TYPE_DATE_TIME) != 0 && !indexonly) {
  163         fputs("<th class=\"header_l",fp_top3);
  164         if (SortTableJs[0]) fputs(" sorttable_nosort",fp_top3);
  165         fputs("\"></th>",fp_top3);
  166     }
  167     if ((TopUserFields & TOPUSERFIELDS_USERID) != 0) {
  168         fputs("<th class=\"header_l",fp_top3);
  169         if (SortTableJs[0]) fputs(" sorttable_alpha",fp_top3);
  170         fprintf(fp_top3,"\">%s</th>",_("USERID"));
  171     }
  172     if ((TopUserFields & TOPUSERFIELDS_USERIP) != 0) {
  173         fputs("<th class=\"header_l",fp_top3);
  174         if (SortTableJs[0]) fputs(" sorttable_alpha",fp_top3);
  175         fprintf(fp_top3,"\">%s</th>",_("USERIP"));
  176     }
  177     if ((TopUserFields & TOPUSERFIELDS_CONNECT) != 0)
  178         fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("CONNECT"));
  179     if ((TopUserFields & TOPUSERFIELDS_BYTES) != 0)
  180         fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("BYTES"));
  181     if ((TopUserFields & TOPUSERFIELDS_SETYB) != 0)
  182         fprintf(fp_top3,"<th class=\"header_l\">%%%s</th>",_("BYTES"));
  183     if ((TopUserFields & TOPUSERFIELDS_IN_CACHE_OUT) != 0)
  184         fprintf(fp_top3,"<th class=\"header_c\" colspan=\"2\">%s</th><th style=\"display:none;\"></th>",_("IN-CACHE-OUT"));
  185     if ((TopUserFields & TOPUSERFIELDS_USED_TIME) != 0)
  186         fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("ELAPSED TIME"));
  187     if ((TopUserFields & TOPUSERFIELDS_MILISEC) != 0)
  188         fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("MILLISEC"));
  189     if ((TopUserFields & TOPUSERFIELDS_PTIME) != 0)
  190         fprintf(fp_top3,"<th class=\"header_l\">%%%s</th>",pgettext("duration","TIME"));
  191 
  192     fputs("</tr></thead>\n",fp_top3);
  193 
  194     greport_prepare();
  195 
  196     if ((line=longline_create())==NULL) {
  197         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),ListFile);
  198         exit(EXIT_FAILURE);
  199     }
  200 
  201     while ((warea=longline_read(fp_top1,line))!=NULL) {
  202         getword_start(&gwarea,warea);
  203         if (getword(user,sizeof(user),&gwarea,'\t')<0) {
  204             debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),ListFile);
  205             exit(EXIT_FAILURE);
  206         }
  207         if (getword_atoll(&nbytes,&gwarea,'\t')<0) {
  208             debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),ListFile);
  209             exit(EXIT_FAILURE);
  210         }
  211         if (getword_atoll(&nacc,&gwarea,'\t')<0) {
  212             debuga(__FILE__,__LINE__,_("Invalid number of accesses in file \"%s\"\n"),ListFile);
  213             exit(EXIT_FAILURE);
  214         }
  215         if (getword_atoll(&elap,&gwarea,'\t')<0) {
  216             debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),ListFile);
  217             exit(EXIT_FAILURE);
  218         }
  219         if (getword_atoll(&incac,&gwarea,'\t')<0) {
  220             debuga(__FILE__,__LINE__,_("Invalid in-cache size in file \"%s\"\n"),ListFile);
  221             exit(EXIT_FAILURE);
  222         }
  223         if (getword_atoll(&oucac,&gwarea,'\n')<0) {
  224             debuga(__FILE__,__LINE__,_("Invalid out-of-cache size in file \"%s\"\n"),ListFile);
  225             exit(EXIT_FAILURE);
  226         }
  227         if (nacc < 1)
  228             continue;
  229         ntopuser=true;
  230         if (TopUsersNum>0 && topcount>=TopUsersNum) break;
  231 
  232         uinfo=userinfo_find_from_id(user);
  233         if (!uinfo) {
  234             debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,ListFile);
  235             exit(EXIT_FAILURE);
  236         }
  237         uinfo->topuser=1;
  238 
  239         fputs("<tr>",fp_top3);
  240 
  241         posicao++;
  242         if ((TopUserFields & TOPUSERFIELDS_NUM) != 0)
  243             fprintf(fp_top3,"<td class=\"data\">%d</td>",posicao);
  244 
  245         if (!indexonly) {
  246             if ((TopUserFields & TOPUSERFIELDS_DATE_TIME) !=0 && (ReportType & REPORT_TYPE_DATE_TIME) != 0) {
  247                 fputs("<td class=\"data2\">",fp_top3);
  248 #ifdef HAVE_GD
  249                 if (Graphs && GraphFont[0]!='\0') {
  250                     greport_day(uinfo);
  251                     //fprintf(fp_top3,"<a href=\"%s/graph_day.png\"><img src=\"%s/graph.png\" title=\"%s\" alt=\"G\"></a>&nbsp;",uinfo->filename,ImageFile,_("Graphic"));
  252                     fprintf(fp_top3,"<a href=\"%s/graph.html\"><img src=\"%s/graph.png\" title=\"%s\" alt=\"G\"></a>&nbsp;",uinfo->filename,ImageFile,_("Graphic"));
  253                 }
  254 #endif
  255                 report_day(uinfo);
  256                 fprintf(fp_top3,"<a href=\"%s/d%s.html\"><img src=\"%s/datetime.png\" title=\"%s\" alt=\"T\"></a></td>",uinfo->filename,uinfo->filename,ImageFile,_("date/time report"));
  257                 day_deletefile(uinfo);
  258             }
  259         }
  260         if ((TopUserFields & TOPUSERFIELDS_USERID) != 0) {
  261             if ((ReportType & REPORT_TYPE_USERS_SITES) == 0 || indexonly)
  262                 fprintf(fp_top3,"<td class=\"data2\">%s</td>",uinfo->label);
  263             else
  264                 fprintf(fp_top3,"<td class=\"data2\"><a href=\"%s/%s.html\">%s</a></td>",uinfo->filename,uinfo->filename,uinfo->label);
  265         }
  266         if ((TopUserFields & TOPUSERFIELDS_USERIP) != 0) {
  267             fprintf(fp_top3,"<td class=\"data2\">%s</td>",uinfo->ip);
  268         }
  269         if ((TopUserFields & TOPUSERFIELDS_CONNECT) != 0) {
  270             fputs("<td class=\"data\"",fp_top3);
  271             if (SortTableJs[0]) fprintf(fp_top3," sorttable_customkey=\"%"PRId64"\"",(int64_t)nacc);
  272             fprintf(fp_top3,">%s</td>",fixnum(nacc,1));
  273         }
  274         if ((TopUserFields & TOPUSERFIELDS_BYTES) != 0) {
  275             fputs("<td class=\"data\"",fp_top3);
  276             if (SortTableJs[0]) fprintf(fp_top3," sorttable_customkey=\"%"PRId64"\"",(int64_t)nbytes);
  277             fprintf(fp_top3,">%s</td>",fixnum(nbytes,1));
  278         }
  279         if ((TopUserFields & TOPUSERFIELDS_SETYB) != 0) {
  280             perc=(Statis->ttnbytes) ? nbytes * 100. / Statis->ttnbytes : 0.;
  281             fprintf(fp_top3,"<td class=\"data\">%3.2lf%%</td>",perc);
  282         }
  283         if ((TopUserFields & TOPUSERFIELDS_IN_CACHE_OUT) != 0) {
  284             inperc=(nbytes) ? incac * 100. / nbytes : 0.;
  285             ouperc=(nbytes) ? oucac * 100. / nbytes : 0.;
  286             fprintf(fp_top3,"<td class=\"data\">%3.2lf%%</td><td class=\"data\">%3.2lf%%</td>",inperc,ouperc);
  287 #ifdef ENABLE_DOUBLE_CHECK_DATA
  288             if ((inperc!=0. || ouperc!=0.) && fabs(inperc+ouperc-100.)>=0.01) {
  289                 debuga(__FILE__,__LINE__,_("The total of the in-cache and cache-miss is not 100%% at position %d (user %s)\n"),posicao,uinfo->label);
  290             }
  291 #endif
  292         }
  293         if ((TopUserFields & TOPUSERFIELDS_USED_TIME) != 0) {
  294             fputs("<td class=\"data\"",fp_top3);
  295             if (SortTableJs[0]) fprintf(fp_top3," sorttable_customkey=\"%"PRId64"\"",(int64_t)elap);
  296             fprintf(fp_top3,">%s</td>",buildtime(elap));
  297         }
  298         if ((TopUserFields & TOPUSERFIELDS_MILISEC) != 0) {
  299             fputs("<td class=\"data\"",fp_top3);
  300             if (SortTableJs[0]) fprintf(fp_top3," sorttable_customkey=\"%"PRId64"\"",(int64_t)elap);
  301             fprintf(fp_top3,">%s</td>",fixnum2(elap,1));
  302         }
  303         if ((TopUserFields & TOPUSERFIELDS_PTIME) != 0) {
  304             perc2=(Statis->ttnelap) ? elap * 100. / Statis->ttnelap : 0.;
  305             fprintf(fp_top3,"<td class=\"data\">%3.2lf%%</td>",perc2);
  306         }
  307 
  308         fputs("</tr>\n",fp_top3);
  309 
  310         topcount++;
  311     }
  312     if (FileObject_Close(fp_top1)) {
  313         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ListFile,FileObject_GetLastCloseError());
  314         exit(EXIT_FAILURE);
  315     }
  316     if (!KeepTempLog && unlink(ListFile)) {
  317         debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),ListFile,strerror(errno));
  318         exit(EXIT_FAILURE);
  319     }
  320     longline_destroy(&line);
  321 
  322     if ((TopUserFields & TOPUSERFIELDS_TOTAL) != 0) {
  323         fputs("<tfoot><tr>",fp_top3);
  324         if ((TopUserFields & TOPUSERFIELDS_NUM) != 0)
  325             fputs("<td></td>",fp_top3);
  326         if ((TopUserFields & TOPUSERFIELDS_DATE_TIME) !=0 && (ReportType & REPORT_TYPE_DATE_TIME) != 0 && !indexonly)
  327             fputs("<td></td>",fp_top3);
  328         if ((TopUserFields & TOPUSERFIELDS_USERIP) != 0)
  329             fprintf(fp_top3,"<th class=\"header_l\" colspan=\"2\">%s</th>",_("TOTAL"));
  330         else
  331             fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("TOTAL"));
  332 
  333         if ((TopUserFields & TOPUSERFIELDS_CONNECT) != 0)
  334             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",fixnum(Statis->ttnacc,1));
  335         if ((TopUserFields & TOPUSERFIELDS_BYTES) != 0)
  336             fprintf(fp_top3,"<th class=\"header_r\">%15s</th>",fixnum(Statis->ttnbytes,1));
  337         if ((TopUserFields & TOPUSERFIELDS_SETYB) != 0)
  338             fputs("<td></td>",fp_top3);
  339         if ((TopUserFields & TOPUSERFIELDS_IN_CACHE_OUT) != 0)
  340         {
  341             inperc=(Statis->ttnbytes) ? Statis->ttnincache * 100. / Statis->ttnbytes : 0.;
  342             ouperc=(Statis->ttnbytes) ? Statis->ttnoucache *100. / Statis->ttnbytes : 0.;
  343             fprintf(fp_top3,"<th class=\"header_r\">%3.2lf%%</th><th class=\"header_r\">%3.2lf%%</th>",inperc,ouperc);
  344 #ifdef ENABLE_DOUBLE_CHECK_DATA
  345             if (fabs(inperc+ouperc-100.)>=0.01) {
  346                 debuga(__FILE__,__LINE__,_("The total of the in-cache and cache-miss is not 100%%\n"));
  347             }
  348 #endif
  349         }
  350         if ((TopUserFields & TOPUSERFIELDS_USED_TIME) != 0)
  351             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",buildtime(Statis->ttnelap));
  352         if ((TopUserFields & TOPUSERFIELDS_MILISEC) != 0)
  353             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",fixnum2(Statis->ttnelap,1));
  354 
  355         fputs("</tr>\n",fp_top3);
  356     }
  357     greport_cleanup();
  358 
  359     if (ntopuser && (TopUserFields & TOPUSERFIELDS_AVERAGE) != 0) {
  360         fputs("<tr>",fp_top3);
  361         if ((TopUserFields & TOPUSERFIELDS_NUM) != 0)
  362             fputs("<td></td>",fp_top3);
  363         if ((TopUserFields & TOPUSERFIELDS_DATE_TIME) !=0 && (ReportType & REPORT_TYPE_DATE_TIME) != 0 && !indexonly)
  364             fputs("<td></td>",fp_top3);
  365         if ((TopUserFields & TOPUSERFIELDS_USERIP) != 0)
  366             fprintf(fp_top3,"<th class=\"header_l\" colspan=\"2\">%s</th>",_("AVERAGE"));
  367         else
  368             fprintf(fp_top3,"<th class=\"header_l\">%s</th>",_("AVERAGE"));
  369 
  370         if ((TopUserFields & TOPUSERFIELDS_CONNECT) != 0)
  371             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",fixnum(Statis->ttnacc/Statis->totuser,1));
  372         if ((TopUserFields & TOPUSERFIELDS_BYTES) != 0) {
  373             nbytes=(Statis->totuser) ? Statis->ttnbytes / Statis->totuser : 0;
  374             fprintf(fp_top3,"<th class=\"header_r\">%15s</th>",fixnum(nbytes,1));
  375         }
  376         if ((TopUserFields & TOPUSERFIELDS_SETYB) != 0)
  377             fputs("<td></td>",fp_top3);
  378         if ((TopUserFields & TOPUSERFIELDS_IN_CACHE_OUT) != 0)
  379             fputs("<td></td><td></td>",fp_top3);
  380         if ((TopUserFields & TOPUSERFIELDS_USED_TIME) != 0)
  381             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",buildtime(Statis->ttnelap/Statis->totuser));
  382         if ((TopUserFields & TOPUSERFIELDS_MILISEC) != 0)
  383             fprintf(fp_top3,"<th class=\"header_r\">%s</th>",fixnum2(Statis->ttnelap/Statis->totuser,1));
  384         fputs("</tr></tfoot>\n",fp_top3);
  385     }
  386 
  387     fputs("</table></div>\n",fp_top3);
  388     write_html_trailer(fp_top3);
  389     if (fclose(fp_top3)==EOF) {
  390         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),top3,strerror(errno));
  391         exit(EXIT_FAILURE);
  392     }
  393 }
  394 
  395 /*!
  396   Generate the top user email report.
  397  */
  398 static void TopUser_TextEmail(const char *ListFile,struct TopUserStatistics *Statis,struct SortInfoStruct *SortInfo)
  399 {
  400     FileObject *fp_top1;
  401     FILE *fp_mail;
  402     longline line;
  403     struct getwordstruct gwarea;
  404     char *warea;
  405     char user[MAX_USER_LEN];
  406     char strip1[MAXLEN], strip2[MAXLEN], strip3[MAXLEN], strip4[MAXLEN], strip5[MAXLEN], strip6[MAXLEN], strip7[MAXLEN];
  407     long long int nbytes;
  408     long long int nacc;
  409     long long int elap, incac, oucac;
  410     double perc=0.00;
  411     double perc2=0.00;
  412     long long int tnbytes=0;
  413     long long int avgacc, avgelap;
  414     int topcount=0;
  415     struct userinfostruct *uinfo;
  416     time_t t;
  417     struct tm *local;
  418     const char *Subject;
  419 
  420     if ((fp_top1=FileObject_Open(ListFile))==NULL) {
  421         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ListFile,FileObject_GetLastOpenError());
  422         exit(EXIT_FAILURE);
  423     }
  424 
  425     fp_mail=Email_OutputFile("topuser");
  426 
  427     if ((line=longline_create())==NULL) {
  428         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),ListFile);
  429         exit(EXIT_FAILURE);
  430     }
  431 
  432     safe_strcpy(strip1,_("Squid User Access Report"),sizeof(strip1));
  433     strip_latin(strip1);
  434     fprintf(fp_mail,"%s\n",strip1);
  435 
  436     snprintf(strip1,sizeof(strip1),_("Sort: %s, %s"),SortInfo->sort_field,SortInfo->sort_order);
  437     strip_latin(strip1);
  438     fprintf(fp_mail,"%s\n",strip1);
  439 
  440     snprintf(strip1,sizeof(strip1),_("Period: %s"),period.text);
  441     strip_latin(strip1);
  442     fprintf(fp_mail,"%s\n\n",strip1);
  443 
  444     safe_strcpy(strip1,_("NUM"),sizeof(strip1));
  445     strip_latin(strip1);
  446     safe_strcpy(strip2,_("USERID"),sizeof(strip2));
  447     strip_latin(strip2);
  448     safe_strcpy(strip3,_("CONNECT"),sizeof(strip3));
  449     strip_latin(strip3);
  450     safe_strcpy(strip4,_("BYTES"),sizeof(strip4));
  451     strip_latin(strip4);
  452     safe_strcpy(strip5,_("ELAPSED TIME"),sizeof(strip5));
  453     strip_latin(strip5);
  454     safe_strcpy(strip6,_("MILLISEC"),sizeof(strip6));
  455     strip_latin(strip6);
  456     safe_strcpy(strip7,pgettext("duration","TIME"),sizeof(strip7));
  457     strip_latin(strip7);
  458 
  459     fprintf(fp_mail,"%-7s %-20s %-9s %-15s %%%-6s %-11s %-10s %%%-7s\n------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",strip1,strip2,strip3,strip4,strip4,strip5,strip6,strip7);
  460 
  461 
  462     while ((warea=longline_read(fp_top1,line))!=NULL) {
  463         getword_start(&gwarea,warea);
  464         if (getword(user,sizeof(user),&gwarea,'\t')<0) {
  465             debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),ListFile);
  466             exit(EXIT_FAILURE);
  467         }
  468         if (getword_atoll(&nbytes,&gwarea,'\t')<0) {
  469             debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),ListFile);
  470             exit(EXIT_FAILURE);
  471         }
  472         if (getword_atoll(&nacc,&gwarea,'\t')<0) {
  473             debuga(__FILE__,__LINE__,_("Invalid number of accesses in file \"%s\"\n"),ListFile);
  474             exit(EXIT_FAILURE);
  475         }
  476         if (getword_atoll(&elap,&gwarea,'\t')<0) {
  477             debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),ListFile);
  478             exit(EXIT_FAILURE);
  479         }
  480         if (getword_atoll(&incac,&gwarea,'\t')<0) {
  481             debuga(__FILE__,__LINE__,_("Invalid in-cache size in file \"%s\"\n"),ListFile);
  482             exit(EXIT_FAILURE);
  483         }
  484         if (getword_atoll(&oucac,&gwarea,'\n')<0) {
  485             debuga(__FILE__,__LINE__,_("Invalid out-of-cache size in file \"%s\"\n"),ListFile);
  486             exit(EXIT_FAILURE);
  487         }
  488         if (nacc < 1)
  489             continue;
  490         if (TopUsersNum>0 && topcount>=TopUsersNum) break;
  491 
  492         uinfo=userinfo_find_from_id(user);
  493         if (!uinfo) {
  494             debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,ListFile);
  495             exit(EXIT_FAILURE);
  496         }
  497         uinfo->topuser=1;
  498 
  499         perc=(Statis->ttnbytes) ? nbytes * 100. / Statis->ttnbytes : 0;
  500         perc2=(Statis->ttnelap) ? elap * 100. / Statis->ttnelap : 0;
  501 
  502         topcount++;
  503 
  504 #if defined(__FreeBSD__)
  505         fprintf(fp_mail,"%7d %20s %8lld %15s %5.2lf%% %10s %10qu %3.2lf%%\n",topcount,uinfo->label,nacc,fixnum(nbytes,1),perc,buildtime(elap),elap,perc2);
  506 #else
  507         fprintf(fp_mail,"%7d %20s %8"PRIu64" %15s %6.2lf%% %10s %10"PRIu64" %3.2lf%%\n",topcount,uinfo->label,(uint64_t)nacc,fixnum(nbytes,1),perc,buildtime(elap),(uint64_t)elap,perc2);
  508 #endif
  509     }
  510     if (FileObject_Close(fp_top1)) {
  511         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ListFile,FileObject_GetLastCloseError());
  512         exit(EXIT_FAILURE);
  513     }
  514     if (!KeepTempLog && unlink(ListFile)) {
  515         debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),ListFile,strerror(errno));
  516         exit(EXIT_FAILURE);
  517     }
  518     longline_destroy(&line);
  519 
  520     // output total
  521     fputs("------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",fp_mail);
  522 #if defined(__FreeBSD__)
  523     fprintf(fp_mail,"%-7s %20s %8qu %15s %8s %9s %10qu\n",_("TOTAL")," ",Statis->ttnacc,fixnum(Statis->ttnbytes,1)," ",buildtime(Statis->ttnelap),Statis->ttnelap);
  524 #else
  525     fprintf(fp_mail,"%-7s %20s %8"PRIu64" %15s %8s %9s %10"PRIu64"\n",_("TOTAL")," ",(uint64_t)Statis->ttnacc,fixnum(Statis->ttnbytes,1)," ",buildtime(Statis->ttnelap),(uint64_t)Statis->ttnelap);
  526 #endif
  527 
  528     // compute and write average
  529     if (Statis->totuser>0) {
  530         tnbytes=Statis->ttnbytes / Statis->totuser;
  531         avgacc=Statis->ttnacc/Statis->totuser;
  532         avgelap=Statis->ttnelap/Statis->totuser;
  533     } else {
  534         tnbytes=0;
  535         avgacc=0;
  536         avgelap=0;
  537     }
  538 
  539     safe_strcpy(strip1,_("AVERAGE"),sizeof(strip1));
  540     strip_latin(strip1);
  541 #if defined(__FreeBSD__)
  542     fprintf(fp_mail,"%-7s %20s %8qu %15s %8s %9s %10qu\n",strip1," ",avgacc,fixnum(tnbytes,1)," ",buildtime(avgelap),avgelap);
  543 #else
  544     fprintf(fp_mail,"%-7s %20s %8"PRIu64" %15s %8s %9s %10"PRIu64"\n",strip1," ",(uint64_t)avgacc,fixnum(tnbytes,1)," ",buildtime(avgelap),(uint64_t)avgelap);
  545 #endif
  546 
  547     t = time(NULL);
  548     local = localtime(&t);
  549     fprintf(fp_mail, "\n%s\n", asctime(local));
  550 
  551     /* TRANSLATORS: This is the e-mail subject. */
  552     Subject=_("Sarg: top user report");
  553     Email_Send(fp_mail,Subject);
  554 }
  555 
  556 /*!
  557  * Produce a report with the user downloading the most data.
  558  */
  559 void topuser(void)
  560 {
  561     FileObject *fp_in = NULL;
  562     FILE *fp_top2;
  563     char wger[MAXLEN];
  564     char top1[MAXLEN];
  565     char top2[MAXLEN];
  566     longline line;
  567     long long int tnacc=0;
  568     long long int tnbytes=0, tnelap=0;
  569     long long int tnincache=0, tnoucache=0;
  570     char *warea;
  571     struct generalitemstruct item;
  572     char olduser[MAX_USER_LEN], csort[MAXLEN];
  573     const char *sfield="-n -k 2,2";
  574     const char *order;
  575     int cstatus;
  576     struct TopUserStatistics Statis;
  577     struct SortInfoStruct SortInfo;
  578 
  579     if (debugz>=LogLevel_Process)
  580         debuga(__FILE__,__LINE__,_("Creating top users report...\n"));
  581 
  582     memset(&Statis,0,sizeof(Statis));
  583 
  584     format_path(__FILE__, __LINE__, wger, sizeof(wger), "%s/sarg-general", outdirname);
  585     if ((fp_in=FileObject_Open(wger))==NULL) {
  586         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wger,FileObject_GetLastOpenError());
  587         exit(EXIT_FAILURE);
  588     }
  589 
  590     format_path(__FILE__, __LINE__, top2, sizeof(top2), "%s/top.tmp", outdirname);
  591     if ((fp_top2=fopen(top2,"w"))==NULL) {
  592         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),top2,strerror(errno));
  593         exit(EXIT_FAILURE);
  594     }
  595 
  596     olduser[0]='\0';
  597 
  598     if ((line=longline_create())==NULL) {
  599         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wger);
  600         exit(EXIT_FAILURE);
  601     }
  602 
  603     while ((warea=longline_read(fp_in,line))!=NULL) {
  604         ger_read(warea,&item,wger);
  605         if (item.total) continue;
  606         if (strcmp(olduser,item.user) != 0) {
  607             Statis.totuser++;
  608 
  609             if (olduser[0] != '\0') {
  610                 /*
  611                 This complicated printf is due to Microsoft's inability to comply with any standard. Msvcrt is unable
  612                 to print a long long int unless it is exactly 64-bits long.
  613                 */
  614                 fprintf(fp_top2,"%s\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",olduser,(uint64_t)tnbytes,(uint64_t)tnacc,(uint64_t)tnelap,(uint64_t)tnincache,(uint64_t)tnoucache);
  615 
  616                 Statis.ttnbytes+=tnbytes;
  617                 Statis.ttnacc+=tnacc;
  618                 Statis.ttnelap+=tnelap;
  619                 Statis.ttnincache+=tnincache;
  620                 Statis.ttnoucache+=tnoucache;
  621             }
  622             safe_strcpy(olduser,item.user,sizeof(olduser));
  623             tnbytes=0;
  624             tnacc=0;
  625             tnelap=0;
  626             tnincache=0;
  627             tnoucache=0;
  628         }
  629 
  630         tnbytes+=item.nbytes;
  631         tnacc+=item.nacc;
  632         tnelap+=item.nelap;
  633         tnincache+=item.incache;
  634         tnoucache+=item.oucache;
  635     }
  636     if (FileObject_Close(fp_in)) {
  637         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wger,FileObject_GetLastCloseError());
  638         exit(EXIT_FAILURE);
  639     }
  640     longline_destroy(&line);
  641 
  642     if (olduser[0] != '\0') {
  643         /*
  644         This complicated printf is due to Microsoft's inability to comply with any standard. Msvcrt is unable
  645         to print a long long int unless it is exactly 64-bits long.
  646         */
  647         fprintf(fp_top2,"%s\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",olduser,(uint64_t)tnbytes,(uint64_t)tnacc,(uint64_t)tnelap,(uint64_t)tnincache,(uint64_t)tnoucache);
  648 
  649         Statis.ttnbytes+=tnbytes;
  650         Statis.ttnacc+=tnacc;
  651         Statis.ttnelap+=tnelap;
  652         Statis.ttnincache+=tnincache;
  653         Statis.ttnoucache+=tnoucache;
  654     }
  655     if (fclose(fp_top2)==EOF) {
  656         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),top2,strerror(errno));
  657         exit(EXIT_FAILURE);
  658     }
  659 
  660 #ifdef ENABLE_DOUBLE_CHECK_DATA
  661     if (Statis.ttnacc!=globstat.nacc || Statis.ttnbytes!=globstat.nbytes || Statis.ttnelap!=globstat.elap ||
  662         Statis.ttnincache!=globstat.incache || Statis.ttnoucache!=globstat.oucache) {
  663         debuga(__FILE__,__LINE__,_("Total statistics mismatch when reading \"%s\" to produce the top users\n"),wger);
  664         exit(EXIT_FAILURE);
  665     }
  666 #endif
  667 
  668     set_total_users(Statis.totuser);
  669 
  670     if ((TopuserSort & TOPUSER_SORT_USER) != 0) {
  671         sfield="-k 1,1";
  672         SortInfo.sort_field=_("user");
  673     } else if ((TopuserSort & TOPUSER_SORT_CONNECT) != 0) {
  674         sfield="-n -k 3,3";
  675         SortInfo.sort_field=_("connect");
  676     } else if ((TopuserSort & TOPUSER_SORT_TIME) != 0) {
  677         sfield="-n -k 4,4";
  678         SortInfo.sort_field=pgettext("duration","time");
  679     } else {
  680         SortInfo.sort_field=_("bytes");
  681     }
  682 
  683     if ((TopuserSort & TOPUSER_SORT_REVERSE) == 0) {
  684         order="";
  685         SortInfo.sort_order=_("normal");
  686     } else {
  687         order="-r";
  688         SortInfo.sort_order=_("reverse");
  689     }
  690 
  691     format_path(__FILE__, __LINE__, top1, sizeof(top1), "%s/top", outdirname);
  692     if (snprintf(csort,sizeof(csort),"sort -T \"%s\" -t \"\t\" %s %s -o \"%s\" \"%s\"", tmp, order, sfield, top1, top2)>=sizeof(csort)) {
  693         debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),top2,top1);
  694         exit(EXIT_FAILURE);
  695     }
  696     cstatus=system(csort);
  697     if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
  698         debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
  699         debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
  700         exit(EXIT_FAILURE);
  701     }
  702 
  703     if (!KeepTempLog && unlink(top2)) {
  704         debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),top2,strerror(errno));
  705         exit(EXIT_FAILURE);
  706     }
  707 
  708     if (email[0])
  709         TopUser_TextEmail(top1,&Statis,&SortInfo);
  710     else
  711         TopUser_HtmlReport(top1,&Statis,&SortInfo);
  712 }