From 6bbb47cf6f0095088c37d87e812a4f3587eed351 Mon Sep 17 00:00:00 2001 From: Frederic Marchal Date: Mon, 20 Jul 2015 14:18:26 +0200 Subject: [PATCH] Generate a top user email with the same options as the html report The produced e-mail is still plain text but it is possible to sort the entries and limit the number of lines with the same options as the html report. The top user list is the only report currently supporting that feature. --- email.c | 286 +++++++------------------------------------------ include/defs.h | 3 +- report.c | 6 +- topuser.c | 166 +++++++++++++++++++++++++++- 4 files changed, 210 insertions(+), 251 deletions(-) diff --git a/email.c b/email.c index 2a70dfe..dc5351e 100644 --- a/email.c +++ b/email.c @@ -31,267 +31,61 @@ extern struct globalstatstruct globstat; #endif -int geramail(const char *dirname, int debug, const char *email, const char *TempDir) -{ - FileObject *fp_in; - FILE *fp_top1, *fp_top2, *fp_top3; - long long int ttnbytes=0, ttnacc=0, tnacc=0; - long long int tnbytes=0, ttnelap=0, tnelap=0; - long long int nacc, nbytes, elap; - long long int avgacc, avgelap; - double perc=0.00; - double perc2=0.00; - int posicao=0; - char olduser[MAX_USER_LEN], csort[MAXLEN]; - char wger[MAXLEN], top1[MAXLEN], top2[MAXLEN], top3[MAXLEN], user[MAX_USER_LEN]; - char strip1[MAXLEN], strip2[MAXLEN], strip3[MAXLEN], strip4[MAXLEN], strip5[MAXLEN], strip6[MAXLEN], strip7[MAXLEN]; - char *buf; - char warea[MAXLEN]; - char Subject[120]; - int totuser=0; - time_t t; - struct tm *local; - int cstatus; - struct getwordstruct gwarea; - struct generalitemstruct item; - longline line; - const struct userinfostruct *uinfo; +//! Name of the file containing the e-mail to send. +static char EmailFileName[MAXLEN]=""; - snprintf(wger,sizeof(wger),"%s/sarg-general",dirname); - if((fp_in=FileObject_Open(wger))==NULL) { - debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wger,FileObject_GetLastOpenError()); - exit(EXIT_FAILURE); - } +/*! + * Generate a file name to write the e-mail and open the file. + * + * \param Module The module for which the e-mail is generated. + * + * \return The file to which the e-mail can be written. + */ +FILE *Email_OutputFile(const char *Module) +{ + FILE *fp; - snprintf(top2,sizeof(top2),"%s/email.int_unsort",dirname); - if((fp_top2=fopen(top2,"w"))==NULL) { - debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),top2,strerror(errno)); - exit(EXIT_FAILURE); + if(strcmp(email,"stdout") == 0) { + EmailFileName[0]='\0'; + return(stdout); } - olduser[0]='\0'; - totuser=0; - - if ((line=longline_create())==NULL) { - debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wger); + snprintf(EmailFileName,sizeof(EmailFileName),"%s/%s.int_unsort",tmp,Module); + if ((fp=fopen(EmailFileName,"w"))==NULL) { + debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),EmailFileName,strerror(errno)); exit(EXIT_FAILURE); } + return(fp); +} - while((buf=longline_read(fp_in,line))!=NULL) { - ger_read(buf,&item,wger); - if(item.total) continue; - if(strcmp(olduser,item.user) != 0) { - totuser++; - - if (olduser[0] != '\0') { -#if defined(__FreeBSD__) - fprintf(fp_top2,"%s\t%qu\t%qu\t%qu\n",olduser,tnbytes,tnacc,tnelap); -#else - fprintf(fp_top2,"%s\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",olduser,(uint64_t)tnbytes,(uint64_t)tnacc,(uint64_t)tnelap); -#endif - ttnbytes+=tnbytes; - ttnacc+=tnacc; - ttnelap+=tnelap; - } - strcpy(olduser,item.user); - tnbytes=0; - tnacc=0; - tnelap=0; - } - - tnbytes+=item.nbytes; - tnacc+=item.nacc; - tnelap+=item.nelap; - } - if (FileObject_Close(fp_in)) { - debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wger,FileObject_GetLastCloseError()); - exit(EXIT_FAILURE); - } - longline_destroy(&line); - - if (olduser[0] != '\0') { -#if defined(__FreeBSD__) - fprintf(fp_top2,"%s\t%qu\t%qu\t%qu\n",olduser,tnbytes,tnacc,tnelap); -#else - fprintf(fp_top2,"%s\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",olduser,(uint64_t)tnbytes,(uint64_t)tnacc,(uint64_t)tnelap); -#endif - ttnbytes+=tnbytes; - ttnacc+=tnacc; - ttnelap+=tnelap; - } +/*! + * Send the e-mail. + * + * \param fp The file opened by Email_OutputFile(). + */ +void Email_Send(FILE *fp,const char *Subject) +{ + char warea[MAXLEN]; + int cstatus; - if (fclose(fp_top2)==EOF) { - debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),top2,strerror(errno)); - exit(EXIT_FAILURE); - } + if (fp==stdout) return;//to stdout -#ifdef ENABLE_DOUBLE_CHECK_DATA - if (ttnacc!=globstat.nacc || ttnbytes!=globstat.nbytes || ttnelap!=globstat.elap) { - debuga(__FILE__,__LINE__,_("Total statistics mismatch when reading \"%s\" to produce the email report\n"),wger); + if (fclose(fp)==EOF) { + debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),EmailFileName,strerror(errno)); exit(EXIT_FAILURE); } -#endif - snprintf(top1,sizeof(top1),"%s/email.int_log",dirname); - if (snprintf(csort,sizeof(csort),"sort -n -T \"%s\" -t \"\t\" -r -k 2,2 -o \"%s\" \"%s\"", TempDir, top1, top2)>=sizeof(csort)) { - debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),top2,top1); - exit(EXIT_FAILURE); - } - cstatus=system(csort); + snprintf(warea,sizeof(warea),"%s -s \"%s\" \"%s\" <\"%s\"",MailUtility,Subject,email,EmailFileName); + if (debug) + debuga(__FILE__,__LINE__,_("Sending mail with command: %s\n"),warea); + cstatus=system(warea); if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) { - debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus)); - debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort); + debuga(__FILE__,__LINE__,_("command return status %d\n"),WEXITSTATUS(cstatus)); + debuga(__FILE__,__LINE__,_("command: %s\n"),warea); exit(EXIT_FAILURE); } - - if (!KeepTempLog && unlink(top2)) { - debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),top2,strerror(errno)); + if (!KeepTempLog && unlink(EmailFileName)) { + debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),EmailFileName,strerror(errno)); exit(EXIT_FAILURE); } - - if((fp_top1=fopen(top1,"r"))==NULL) { - debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),top1,strerror(errno)); - exit(EXIT_FAILURE); - } - - if(strcmp(email,"stdout") == 0) { - fp_top3=stdout; - } else { - snprintf(top3,sizeof(top3),"%s/report",dirname); - if((fp_top3=fopen(top3,"w"))==NULL) { - debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),top3,strerror(errno)); - exit(EXIT_FAILURE); - } - } - - safe_strcpy(strip1,_("Squid User Access Report"),sizeof(strip1)); - strip_latin(strip1); - fprintf(fp_top3,"%s\n",strip1); - - safe_strcpy(strip1,_("Decreasing Access (bytes)"),sizeof(strip1)); - strip_latin(strip1); - fprintf(fp_top3,"%s\n",strip1); - - safe_strcpy(strip1,_("Period"),sizeof(strip1)); - strip_latin(strip1); - fprintf(fp_top3,"%s %s\n\n",strip1,period.text); - - safe_strcpy(strip1,_("NUM"),sizeof(strip1)); - strip_latin(strip1); - safe_strcpy(strip2,_("USERID"),sizeof(strip2)); - strip_latin(strip2); - safe_strcpy(strip3,_("CONNECT"),sizeof(strip3)); - strip_latin(strip3); - safe_strcpy(strip4,_("BYTES"),sizeof(strip4)); - strip_latin(strip4); - safe_strcpy(strip5,_("ELAPSED TIME"),sizeof(strip5)); - strip_latin(strip5); - safe_strcpy(strip6,_("MILLISEC"),sizeof(strip6)); - strip_latin(strip6); - safe_strcpy(strip7,pgettext("duration","TIME"),sizeof(strip7)); - strip_latin(strip7); - - fprintf(fp_top3,"%-7s %-20s %-8s %-15s %%%-6s %-10s %-10s %%%-7s\n------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",strip1,strip2,strip3,strip4,strip4,strip5,strip6,strip7); - - while ((TopUsersNum==0 || posicaolabel,nacc,fixnum(nbytes,1),perc,buildtime(elap),elap,perc2); -#else - fprintf(fp_top3,"%7d %20s %8"PRIu64" %15s %3.2lf%% %10s %10"PRIu64" %3.2lf%%\n",posicao,uinfo->label,(uint64_t)nacc,fixnum(nbytes,1),perc,buildtime(elap),(uint64_t)elap,perc2); -#endif - } - - // output total - fputs("------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",fp_top3); -#if defined(__FreeBSD__) - fprintf(fp_top3,"%-7s %20s %8qu %15s %8s %9s %10qu\n",_("TOTAL")," ",ttnacc,fixnum(ttnbytes,1)," ",buildtime(ttnelap),ttnelap); -#else - fprintf(fp_top3,"%-7s %20s %8"PRIu64" %15s %8s %9s %10"PRIu64"\n",_("TOTAL")," ",(uint64_t)ttnacc,fixnum(ttnbytes,1)," ",buildtime(ttnelap),(uint64_t)ttnelap); -#endif - - // compute and write average - if (totuser>0) { - tnbytes=(totuser) ? ttnbytes / totuser : 0; - avgacc=ttnacc/totuser; - avgelap=ttnelap/totuser; - } else { - tnbytes=0; - avgacc=0; - avgelap=0; - } - - safe_strcpy(strip1,_("AVERAGE"),sizeof(strip1)); - strip_latin(strip1); -#if defined(__FreeBSD__) - fprintf(fp_top3,"%-7s %20s %8qu %15s %8s %9s %10qu\n",strip1," ",avgacc,fixnum(tnbytes,1)," ",buildtime(avgelap),avgelap); -#else - fprintf(fp_top3,"%-7s %20s %8"PRIu64" %15s %8s %9s %10"PRIu64"\n",strip1," ",(uint64_t)avgacc,fixnum(tnbytes,1)," ",buildtime(avgelap),(uint64_t)avgelap); -#endif - - if (fclose(fp_top1)==EOF) { - debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),top1,strerror(errno)); - exit(EXIT_FAILURE); - } - if (!KeepTempLog && unlink(top1)) { - debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),top1,strerror(errno)); - exit(EXIT_FAILURE); - } - - t = time(NULL); - local = localtime(&t); - fprintf(fp_top3, "\n%s\n", asctime(local)); - - if(strcmp(email,"stdout") != 0) { - if (fclose(fp_top3)==EOF) { - debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),top3,strerror(errno)); - exit(EXIT_FAILURE); - } - - /* TRANSLATORS: The string is formatted using strftime. You can use - any string formatting marker allowed by strftime. */ - strftime(Subject,sizeof(Subject),_("SARG report, %c"),local); - snprintf(warea,sizeof(warea),"%s -s \"%s\" \"%s\" <\"%s\"",MailUtility,Subject,email,top3); - if (debug) - debuga(__FILE__,__LINE__,_("Sending mail with command: %s\n"),warea); - cstatus=system(warea); - if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) { - debuga(__FILE__,__LINE__,_("command return status %d\n"),WEXITSTATUS(cstatus)); - debuga(__FILE__,__LINE__,_("command: %s\n"),warea); - exit(EXIT_FAILURE); - } - } - - //unlinkdir(TempDir,0); - - return (0); } diff --git a/include/defs.h b/include/defs.h index a40c1ce..101ce9a 100644 --- a/include/defs.h +++ b/include/defs.h @@ -214,7 +214,8 @@ bool is_download_suffix(const char *url); void download_cleanup(void); // email.c -int geramail(const char *dirname, int debug, const char *email, const char *TempDir); +FILE *Email_OutputFile(const char *Module); +void Email_Send(FILE *fp,const char *Subject); // exclude.c void gethexclude(const char *hexfile, int debug); diff --git a/report.c b/report.c index acf37fe..dba3cd0 100644 --- a/report.c +++ b/report.c @@ -100,9 +100,9 @@ void gerarel(void) exit(EXIT_FAILURE); } } else { - if (snprintf(outdirname,sizeof(outdirname),"%semailrep",outdir)>=sizeof(outdirname)) { + if (snprintf(outdirname,sizeof(outdirname),"%s/emailrep",tmp)>=sizeof(outdirname)) { debuga(__FILE__,__LINE__,_("Path too long: ")); - debuga_more("%semailrep\n",outdir); + debuga_more("%s/emailrep\n",tmp); exit(EXIT_FAILURE); } my_mkdir(outdirname); @@ -438,7 +438,7 @@ void gerarel(void) if(SuccessfulMsg) debuga(__FILE__,__LINE__,_("Successful report generated on %s\n"),outdirname); } else { - geramail(outdirname, debug, email, tmp); + topuser(); if((strcmp(email,"stdout") != 0) && SuccessfulMsg) debuga(__FILE__,__LINE__,_("Successful report generated and sent to %s\n"),email); diff --git a/topuser.c b/topuser.c index 19bd2bc..762478f 100644 --- a/topuser.c +++ b/topuser.c @@ -393,6 +393,167 @@ static void TopUser_HtmlReport(const char *ListFile,struct TopUserStatistics *St } } +/*! + Generate the top user email report. + */ +static void TopUser_TextEmail(const char *ListFile,struct TopUserStatistics *Statis,struct SortInfoStruct *SortInfo) +{ + FileObject *fp_top1; + FILE *fp_mail; + longline line; + struct getwordstruct gwarea; + char *warea; + char user[MAX_USER_LEN]; + char strip1[MAXLEN], strip2[MAXLEN], strip3[MAXLEN], strip4[MAXLEN], strip5[MAXLEN], strip6[MAXLEN], strip7[MAXLEN]; + long long int nbytes; + long long int nacc; + long long int elap, incac, oucac; + double perc=0.00; + double perc2=0.00; + long long int tnbytes=0; + long long int avgacc, avgelap; + int topcount=0; + struct userinfostruct *uinfo; + time_t t; + struct tm *local; + const char *Subject; + + if ((fp_top1=FileObject_Open(ListFile))==NULL) { + debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ListFile,FileObject_GetLastOpenError()); + exit(EXIT_FAILURE); + } + + fp_mail=Email_OutputFile("topuser"); + + if ((line=longline_create())==NULL) { + debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + + safe_strcpy(strip1,_("Squid User Access Report"),sizeof(strip1)); + strip_latin(strip1); + fprintf(fp_mail,"%s\n",strip1); + + snprintf(strip1,sizeof(strip1),_("Sort: %s, %s"),SortInfo->sort_field,SortInfo->sort_order); + strip_latin(strip1); + fprintf(fp_mail,"%s\n",strip1); + + snprintf(strip1,sizeof(strip1),_("Period: %s"),period.text); + strip_latin(strip1); + fprintf(fp_mail,"%s\n\n",strip1); + + safe_strcpy(strip1,_("NUM"),sizeof(strip1)); + strip_latin(strip1); + safe_strcpy(strip2,_("USERID"),sizeof(strip2)); + strip_latin(strip2); + safe_strcpy(strip3,_("CONNECT"),sizeof(strip3)); + strip_latin(strip3); + safe_strcpy(strip4,_("BYTES"),sizeof(strip4)); + strip_latin(strip4); + safe_strcpy(strip5,_("ELAPSED TIME"),sizeof(strip5)); + strip_latin(strip5); + safe_strcpy(strip6,_("MILLISEC"),sizeof(strip6)); + strip_latin(strip6); + safe_strcpy(strip7,pgettext("duration","TIME"),sizeof(strip7)); + strip_latin(strip7); + + fprintf(fp_mail,"%-7s %-20s %-9s %-15s %%%-6s %-11s %-10s %%%-7s\n------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",strip1,strip2,strip3,strip4,strip4,strip5,strip6,strip7); + + + while ((warea=longline_read(fp_top1,line))!=NULL) { + getword_start(&gwarea,warea); + if (getword(user,sizeof(user),&gwarea,'\t')<0) { + debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (getword_atoll(&nbytes,&gwarea,'\t')<0) { + debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (getword_atoll(&nacc,&gwarea,'\t')<0) { + debuga(__FILE__,__LINE__,_("Invalid number of accesses in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (getword_atoll(&elap,&gwarea,'\t')<0) { + debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (getword_atoll(&incac,&gwarea,'\t')<0) { + debuga(__FILE__,__LINE__,_("Invalid in-cache size in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (getword_atoll(&oucac,&gwarea,'\n')<0) { + debuga(__FILE__,__LINE__,_("Invalid out-of-cache size in file \"%s\"\n"),ListFile); + exit(EXIT_FAILURE); + } + if (nacc < 1) + continue; + if (TopUsersNum>0 && topcount>=TopUsersNum) break; + + uinfo=userinfo_find_from_id(user); + if (!uinfo) { + debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,ListFile); + exit(EXIT_FAILURE); + } + uinfo->topuser=1; + + perc=(Statis->ttnbytes) ? nbytes * 100. / Statis->ttnbytes : 0; + perc2=(Statis->ttnelap) ? elap * 100. / Statis->ttnelap : 0; + + topcount++; + +#if defined(__FreeBSD__) + 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); +#else + 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); +#endif + } + if (FileObject_Close(fp_top1)) { + debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ListFile,FileObject_GetLastCloseError()); + exit(EXIT_FAILURE); + } + if (!KeepTempLog && unlink(ListFile)) { + debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),ListFile,strerror(errno)); + exit(EXIT_FAILURE); + } + longline_destroy(&line); + + // output total + fputs("------- -------------------- -------- --------------- ------- ---------- ---------- -------\n",fp_mail); +#if defined(__FreeBSD__) + fprintf(fp_mail,"%-7s %20s %8qu %15s %8s %9s %10qu\n",_("TOTAL")," ",Statis->ttnacc,fixnum(Statis->ttnbytes,1)," ",buildtime(Statis->ttnelap),Statis->ttnelap); +#else + 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); +#endif + + // compute and write average + if (Statis->totuser>0) { + tnbytes=Statis->ttnbytes / Statis->totuser; + avgacc=Statis->ttnacc/Statis->totuser; + avgelap=Statis->ttnelap/Statis->totuser; + } else { + tnbytes=0; + avgacc=0; + avgelap=0; + } + + safe_strcpy(strip1,_("AVERAGE"),sizeof(strip1)); + strip_latin(strip1); +#if defined(__FreeBSD__) + fprintf(fp_mail,"%-7s %20s %8qu %15s %8s %9s %10qu\n",strip1," ",avgacc,fixnum(tnbytes,1)," ",buildtime(avgelap),avgelap); +#else + 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); +#endif + + t = time(NULL); + local = localtime(&t); + fprintf(fp_mail, "\n%s\n", asctime(local)); + + /* TRANSLATORS: This is the e-mail subject. */ + Subject=_("Sarg: top user report"); + Email_Send(fp_mail,Subject); +} + /*! * Produce a report with the user downloading the most data. */ @@ -545,5 +706,8 @@ void topuser(void) exit(EXIT_FAILURE); } - TopUser_HtmlReport(top1,&Statis,&SortInfo); + if (email[0]) + TopUser_TextEmail(top1,&Statis,&SortInfo); + else + TopUser_HtmlReport(top1,&Statis,&SortInfo); } -- 2.47.2