/**************************************************************************** MailListStat - print useful statistics on email messages Output of computed stats Copyright (C) 2001-2003 Marek Podmaka This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ #include "mls.h" #include "mls_lang.h" #include "mls_stat.h" extern int lang; extern int graph; extern int onlytitle; extern FILE *fOut; extern time_t t, t_oldest, t_newest; extern long nSprav, nDlzka; extern long nDen[31]; extern long nHod[24]; extern long nDOW[ 7]; extern long nMon[12]; extern nQptr msgQ; extern nDptr msgD; extern nTptr zozA, zozS, zozQ, zozM, zozAt, zozAa; /* ***** GetCount ******************************************************** */ long GetCount(nTptr first) { // return number of members in list nTptr akt; long count=0; for (akt=first; akt!=NULL; akt=akt->next) count++; return count; } /* ***** GetSum ********************************************************** */ long GetSum(long pole[], int max_index) { // return sum of elements in array long sum=0; int i; for (i=0; i < max_index; i++) sum+=pole[i]; return sum; } /* ***** GetSumZoz ******************************************************* */ long GetSumZoz(nTptr first, int max_index) { // return sum of count elements of first max_index members of list long sum=0; int i; nTptr akt; for (akt=first, i=0; (i < max_index) && (akt!=NULL); i++, akt=akt->next) sum+=akt->count; return sum; } /* ***** GetSumZozQ ****************************************************** */ long GetSumZozQ(nTptr first) { // return sum of quote elements of all members of list long sum=0; nTptr akt; for (akt=first; akt!=NULL; akt=akt->next) sum+=akt->quote; return sum; } /* ***** PrintTop ******************************************************** */ void PrintTop(nTptr first, int top) { // print TOP table nTptr akt; int i; for (i=1, akt=first; (i <= top) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"|%3i | %-44.44s |%5li |%6.2f %% |\n",i,akt->text,akt->count,(float)akt->count/nSprav*100); } } /* ***** PrintTopHtml **************************************************** */ void PrintTopHtml(nTptr first, int top) { // print TOP table (HTML format) nTptr akt; int i; for (i=1, akt=first; (i <= top) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut," %i%s%li%6.2f %%\n",(i%2)?"topXXtr1":"topXXtr2",i,akt->text,akt->count,(float)akt->count/nSprav*100); } } /* ***** PrintTopQ ******************************************************* */ void PrintTopQ(nTptr first, int top) { // print TOP quote table nTptr akt; int i; for (i=1, akt=first; (i <= top) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"|%3i | %-45.45s |%6.2f %% |\n",i,akt->text,(float)akt->count/100); } } /* ***** PrintGraph ****************************************************** */ void PrintGraph(long pole[], int max_index, int hole) { // print 10line graph // will print MAX_INDEX bars which will be HOLE chars apart long max; char line[80]; // one line of output int i,j; float a; // initialization if (hole<1) myWarn("Invalid arguments passed to PrintGraph()!","(hole too small)",4); if (hole*max_index > 80) myWarn("Invalid arguments passed to PrintGraph()!","(max_index too big)",4); max=pole[0]; memset(line, 'E', 79); line[79]=line[hole*max_index]='\0'; for (i=0; i < max_index; i++) { if (pole[i] > max) max=pole[i]; // find max. for (j=1; j < hole; j++) line[i*hole+j]='-'; // spaces between columns } // graph + description of y-axis for (i=10; i > 0; i--) { // for each line for (j=0; j < max_index; j++) { a=(float)pole[j]/max*10; line[j*hole]=( (int)a>=i )?'#':'-'; } fprintf(fOut,"\n%3i%% -%s", i*10, line); if (i==10) fprintf(fOut," - %li", max); if (i== 9) fprintf(fOut," %s", langMess[lang]); } // footer - description of x-axis for (i=0; i < max_index; i++) { line[i*hole]='*'; for (j=1; j < hole; j++) line[i*hole+j]=' '; // space between columns } fprintf(fOut,"\n %s\n", line); } /* ***** PrintGraphHtml ************************************************** */ void PrintGraphHtml(long data[], char desc[][SNUMB_LEN], int max_index, char *sHeader) { // print graph using HTML tables int i; long max; float a; /* ing j; char ch[11]; // used for ALT in IMG tag */ max=data[0]; for (i=0; i < max_index; i++) if (data[i] > max) max=data[i]; // find max. fprintf(fOut,"\n"); // GRAPH w/ HORIZONTAL BARS (and ALT tags) /* fprintf(fOut,"
%s", sHeader); fprintf(fOut," %s\n", langMess[lang]); for (i=0; i < max_index; i++) { a=(float)data[i]/max; for (j=0; j < a*10; j++) ch[j]='#'; // print # for every 10% ch[j]='\0'; a*=550; // max. width of bar fprintf(fOut,"
%s", desc[i]); fprintf(fOut," \"%s\" %lu\n", ch, (int)a, data[i]); } */ // GRAPH w/ VERTICAL BARS fprintf(fOut, "
%s\n", langMess[lang]); for (i=0; i < max_index; i++) { a=(float)data[i]/max; a*=150; // max. height of bar fprintf(fOut,"%lu
", data[i]); fprintf(fOut,"\"|\"\n", (int)a); } fprintf(fOut, "
%s\n", sHeader); for (i=0; i < max_index; i++) fprintf(fOut,"%s", desc[i]); fprintf(fOut,"
\n"); } /* ***** PrintStatText *************************************************** */ void PrintStatText(int topXX, char *title) { // print statistics in plain-text format long i; struct tm *tm1; char string[801]; nTptr akt; if (nSprav > 0) { tm1=localtime(&t_oldest); sprintf(string,"\n %s %i.%i.%i", langTit1[lang], tm1->tm_mday, tm1->tm_mon+1, tm1->tm_year+1900); tm1=localtime(&t_newest); sprintf(string+strlen(string)," %s %i.%i.%i", langTit2[lang], tm1->tm_mday, tm1->tm_mon+1, tm1->tm_year+1900); if (title[0]!='\0') sprintf(string+strlen(string)," %s %s",langTit3[lang],title); if (onlytitle==1) sprintf(string, "%s", title); // only user-defined title fprintf(fOut,"%s\n",string); for (i=0; inext) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"|%3li | %-52.52s | %6.1f |\n",i,akt->text,(float)akt->count/1024); } fprintf(fOut,"+----+------------------------------------------------------+--------+\n"); // TOP AUTHORS by average size of msgs fprintf(fOut,"\n***** %s\n",langTOPauthorSizeA[lang]); fprintf(fOut,"+----+----%s-------------------------------------------+-bytes-+\n",langGAuthor[lang]); for (i=1, akt=zozAa; (i <= topXX) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"|%3li | %-53.53s |%6lu |\n",i,akt->text,akt->count); } fprintf(fOut,"+----+-------------------------------------------------------+-------+\n"); // TOP SUBJ fprintf(fOut,"\n***** %s\n",langTOPsubj[lang]); // fprintf(fOut,"+----+----Subject-----------------------------------+%s+-Percent-+\n",langGMess[lang]); fprintf(fOut,"+----+---%s----------------------------------+%s+%s+\n",langSubject[lang],langGMess[lang],langPercent[lang]); PrintTop(zozS, topXX); fprintf(fOut,"+----+----------------------------------------------+------+---------+\n"); i=nSprav - GetSumZoz(zozS, topXX); fprintf(fOut,"| | %-44.44s |%5li | %5.2f %% |\n",langOstE[lang],i,(float)i/nSprav*100); fprintf(fOut,"+----+----------------------------------------------+------+---------+\n"); // TOP MAILERS fprintf(fOut,"\n***** %s\n",langTOPmail[lang]); // fprintf(fOut,"+----+----Mailer------------------------------------+%s+-Percent-+\n",langGMess[lang]); fprintf(fOut,"+----+---%s----------------------------------+%s+%s+\n",langMailer[lang],langGMess[lang],langPercent[lang]); PrintTop(zozM, topXX); fprintf(fOut,"+----+----------------------------------------------+------+---------+\n"); i=nSprav - GetSumZoz(zozM, topXX); fprintf(fOut,"| | %-44.44s |%5li | %5.2f %% |\n",langOstE[lang],i,(float)i/nSprav*100); fprintf(fOut,"+----+----------------------------------------------+------+---------+\n"); // TOP QUOTING fprintf(fOut,"\n***** %s\n",langTOPquote[lang]); // fprintf(fOut,"+----+----%s-----------------------------------------+-Percent-+\n",langGAuthor[lang]); fprintf(fOut,"+----+----%s-----------------------------------------+%s+\n",langGAuthor[lang],langPercent[lang]); for (i=1, akt=zozQ; (i <= topXX) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"|%3li | %-45.45s |%6.2f %% |\n",i,akt->text,(float)akt->count/100); } fprintf(fOut,"+----+-----------------------------------------------------+---------+\n"); fprintf(fOut,"| | %-45.45s | %5.2f %% |\n",langAvg[lang],(float)GetSumZozQ(zozQ)/nDlzka*100); fprintf(fOut,"+----+-----------------------------------------------------+---------+\n"); // Hours of day if (graph & G_DAY) { fprintf(fOut,"\n***** %s\n",langGhour[lang]); PrintGraph(nHod,24,2); fprintf(fOut,"%s 0 5 11 17 23\n",langHour[lang]); if (GetSum(nHod, 24) != nSprav) fprintf(fOut,"!!!!! %s: %li %s.\n",langWarn[lang],nSprav - GetSum(nHod,24),langCount[lang]); } // Days of month if (graph & G_MONTH) { fprintf(fOut,"\n\n***** %s\n",langGday[lang]); PrintGraph(nDen,31,2); fprintf(fOut," %s 1 6 12 18 24 31\n",langDay[lang]); if (GetSum(nDen, 31) != nSprav) fprintf(fOut,"!!!!! %s: %li %s.\n",langWarn[lang],nSprav - GetSum(nDen,31),langCount[lang]); } // Days of week if (graph & G_WEEK) { fprintf(fOut,"\n\n***** %s\n",langGdow[lang]); PrintGraph(nDOW,7,4); fprintf(fOut," %s\n",langDOW[lang]); if (GetSum(nDOW, 7) != nSprav) fprintf(fOut,"!!!!! %s: %li %s.\n",langWarn[lang],nSprav - GetSum(nDOW,7),langCount[lang]); } // Months of year if (graph & G_YEAR) { fprintf(fOut,"\n\n***** %s\n",langGmon[lang]); PrintGraph(nMon,12,4); fprintf(fOut," %s\n",langMON[lang]); if (GetSum(nMon, 12) != nSprav) fprintf(fOut,"!!!!! %s: %li %s.\n",langWarn[lang],nSprav - GetSum(nMon,12),langCount[lang]); } fprintf(fOut,"\n\n***** %s\n",langMaxQuot[lang]); fprintf(fOut," %s %s\n",langAuth[lang], msgQ->auth); fprintf(fOut," %s %s\n",langSubj[lang], msgQ->subj); fprintf(fOut," %s %s\n",langDate[lang], msgQ->date); fprintf(fOut," %s %0.2f%% / %li %s\n",langRate[lang], msgQ->perc*100,msgQ->size, langByte[lang]); fprintf(fOut,"\n***** %s\n",langMaxLeng[lang]); fprintf(fOut," %s %s\n",langAuth[lang], msgD->auth); fprintf(fOut," %s %s\n",langSubj[lang], msgD->subj); fprintf(fOut," %s %s\n",langDate[lang], msgD->date); fprintf(fOut," %s %li %s\n",langSize[lang], msgD->size, langByte[lang]); fprintf(fOut,"\n***** %s\n",langMaxSubj[lang]); fprintf(fOut," %s %s\n" ,langSubj[lang], zozS->text); fprintf(fOut," %s %li\n",langNumb[lang], zozS->count); fprintf(fOut," %s %li %s\n",langSSiz[lang], zozS->size, langByte[lang]); fprintf(fOut,"\n***** %s\n",langEndStat[lang]); fprintf(fOut," %s %li\n",langTotMess[lang], nSprav); fprintf(fOut," %s %li\n",langTotAuth[lang], GetCount(zozA)); fprintf(fOut," %s %li\n",langTotSubj[lang], GetCount(zozS)); fprintf(fOut," %s %li %s\n",langTotLeng[lang], nDlzka, langByte[lang]); fprintf(fOut," %s %li %s\n",langAvgLeng[lang], nDlzka/nSprav, langByte[lang]); fprintf(fOut,"\n"); fprintf(fOut,"***** Generated by MailListStat v%s, (C) 2001-2003 \n",VERSION); fprintf(fOut,"***** See http://freshmeat.net/projects/mls for details...\n"); } else fprintf(fOut,"\nNo messages found. Therefore no stats can be computed!\n"); } /* ***** PrintStatHtml *************************************************** */ void PrintStatHtml(int topXX, char *title, short mode) { // print statistics in HTML format long i; struct tm *tm1; nTptr akt; char sNumb[32][SNUMB_LEN]; for (i=0; i <= 31; i++) sprintf(sNumb[i], "%lu", i); // for description if (mode!=2) { // don't print HTML header/footer in html2 mode fprintf(fOut,"\n"); fprintf(fOut,"\n"); fprintf(fOut," \n",langCharset[lang]); fprintf(fOut," \n"); fprintf(fOut," \n"); fprintf(fOut," \n"); fprintf(fOut," \n"); fprintf(fOut," \n"); fprintf(fOut," MailListStat - Statistics"); if (title[0]!='\0') fprintf(fOut," (%s)",title); fprintf(fOut,"\n"); fprintf(fOut,"\n"); fprintf(fOut,"\n"); } if (nSprav > 0) { fprintf(fOut,"\n

"); if (onlytitle==1) fprintf(fOut, "%s", title); // only user-defined title else { // normal title tm1=localtime(&t_oldest); fprintf(fOut,"%s %i.%i.%i ", langTit1[lang], tm1->tm_mday, tm1->tm_mon+1, tm1->tm_year+1900); tm1=localtime(&t_newest); fprintf(fOut,"%s %i.%i.%i" , langTit2[lang], tm1->tm_mday, tm1->tm_mon+1, tm1->tm_year+1900); if (title[0]!='\0') fprintf(fOut,"
%s %s",langTit3[lang],title); } fprintf(fOut,"

\n"); fprintf(fOut,"\n"); // marker for PHP wrapper // TOP AUTHORS by no. of msgs fprintf(fOut,"\n

%s

\n",langTOPpeople[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); // fprintf(fOut,"
  %s  %s  Percent \n",langGAuthorHtml[lang],langGMessHtml[lang]); fprintf(fOut,"  %s  %s  %s \n",langGAuthorHtml[lang],langGMessHtml[lang],langPercentHtml[lang]); PrintTopHtml(zozA, topXX); i=nSprav - GetSumZoz(zozA, topXX); fprintf(fOut,"
 %s%li%5.2f %%\n",langOstI[lang],i,(float)i/nSprav*100); fprintf(fOut,"
\n"); // TOP AUTHORS by total size of msgs fprintf(fOut,"\n

%s

\n",langTOPauthorSizeT[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); fprintf(fOut,"
  %s  KBytes \n",langGAuthorHtml[lang]); for (i=1, akt=zozAt; (i <= topXX) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"
%li%s%6.1f\n",(i%2)?"topXXtr1":"topXXtr2",i,akt->text,(float)akt->count/1024); } fprintf(fOut,"
\n"); // TOP AUTHORS by average size of msgs fprintf(fOut,"\n

%s

\n",langTOPauthorSizeA[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); fprintf(fOut,"
  %s  bytes \n",langGAuthorHtml[lang]); for (i=1, akt=zozAa; (i <= topXX) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"
%li%s%lu\n",(i%2)?"topXXtr1":"topXXtr2",i,akt->text,akt->count); } fprintf(fOut,"
\n"); // TOP SUBJ fprintf(fOut,"\n

%s

\n",langTOPsubj[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); // fprintf(fOut,"
  Subject  %s  Percent \n",langGMessHtml[lang]); fprintf(fOut,"  %s  %s  %s \n",langSubjectHtml[lang],langGMessHtml[lang],langPercentHtml[lang]); PrintTopHtml(zozS, topXX); i=nSprav - GetSumZoz(zozS, topXX); fprintf(fOut,"
 %s%li%5.2f %%\n",langOstE[lang],i,(float)i/nSprav*100); fprintf(fOut,"
\n"); // TOP MAILERS fprintf(fOut,"\n

%s

\n",langTOPmail[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); // fprintf(fOut,"
  Mailer  %s  Percent \n",langGMessHtml[lang]); fprintf(fOut,"  %s  %s  %s \n",langMailerHtml[lang],langGMessHtml[lang],langPercentHtml[lang]); PrintTopHtml(zozM, topXX); i=nSprav - GetSumZoz(zozM, topXX); fprintf(fOut,"
 %s%li%5.2f %%\n",langOstE[lang],i,(float)i/nSprav*100); fprintf(fOut,"
\n"); // TOP QUOTING fprintf(fOut,"\n

%s

\n",langTOPquote[lang]); fprintf(fOut,"\n"); fprintf(fOut," "); // fprintf(fOut,"
  %s  Percent \n",langGAuthorHtml[lang]); fprintf(fOut,"  %s  %s \n",langGAuthorHtml[lang],langPercentHtml[lang]); for (i=1, akt=zozQ; (i <= topXX) && (akt!=NULL); i++, akt=akt->next) { if (akt->text[0]=='\0') myCopy(akt->text, langUnknown[lang], MAX_TEXT); fprintf(fOut,"
%li%s%6.2f %%\n",(i%2)?"topXXtr1":"topXXtr2",i,akt->text,(float)akt->count/100); } fprintf(fOut,"
 %s%6.2f %%\n",langAvg[lang],(float)GetSumZozQ(zozQ)/nDlzka*100); fprintf(fOut,"
\n"); // Hours of day if (graph & G_DAY) { fprintf(fOut,"\n

%s

\n",langGhour[lang]); PrintGraphHtml(nHod, sNumb, 24, langHour[lang]); if (GetSum(nHod, 24) != nSprav) fprintf(fOut,"
%s: %li %s.
\n",langWarn[lang],nSprav - GetSum(nHod,24),langCount[lang]); } // Days of month if (graph & G_MONTH) { fprintf(fOut,"\n

%s

\n",langGday[lang]); PrintGraphHtml(nDen, sNumb+1, 31, langDay[lang]); if (GetSum(nDen, 31) != nSprav) fprintf(fOut,"
%s: %li %s.
\n",langWarn[lang],nSprav - GetSum(nDen,31),langCount[lang]); } // Days of week if (graph & G_WEEK) { for (i=0; i <= 7; i++) { // fill the sNumb array with week-day names from langDOW[lang] strncpy(sNumb[i], langDOW[lang]+i*4, 3); sNumb[i][3]='\0'; } fprintf(fOut,"\n

%s

\n",langGdow[lang]); PrintGraphHtml(nDOW, sNumb, 7, ""); if (GetSum(nDOW, 7) != nSprav) fprintf(fOut,"
%s: %li %s.
\n",langWarn[lang],nSprav - GetSum(nDOW, 7),langCount[lang]); } // Months of year if (graph & G_YEAR) { for (i=0; i <=12; i++) { // fill the sNumb array with month-names from langMON[lang] strncpy(sNumb[i], langMON[lang]+i*4, 3); sNumb[i][3]='\0'; } fprintf(fOut,"\n

%s

\n",langGmon[lang]); PrintGraphHtml(nMon, sNumb,12, ""); if (GetSum(nMon, 12) != nSprav) fprintf(fOut,"
%s: %li %s.
\n",langWarn[lang],nSprav - GetSum(nMon,12),langCount[lang]); } fprintf(fOut,"\n

%s

\n",langMaxQuot[lang]); fprintf(fOut,"\n"); fprintf(fOut,"
%s %s \n",langAuth[lang], msgQ->auth); fprintf(fOut,"
%s %s \n",langSubj[lang], msgQ->subj); fprintf(fOut,"
%s %s \n",langDate[lang], msgQ->date); fprintf(fOut,"
%s %0.2f%% / %li %s\n",langRate[lang], msgQ->perc*100,msgQ->size, langByte[lang]); fprintf(fOut,"
\n"); fprintf(fOut,"\n

%s

\n",langMaxLeng[lang]); fprintf(fOut,"\n"); fprintf(fOut,"
%s %s\n",langAuth[lang], msgD->auth); fprintf(fOut,"
%s %s\n",langSubj[lang], msgD->subj); fprintf(fOut,"
%s %s\n",langDate[lang], msgD->date); fprintf(fOut,"
%s %li %s\n",langSize[lang], msgD->size, langByte[lang]); fprintf(fOut,"
\n"); fprintf(fOut,"\n

%s

\n",langMaxSubj[lang]); fprintf(fOut,"\n"); fprintf(fOut,"
%s %s\n" ,langSubj[lang], zozS->text); fprintf(fOut,"
%s %li\n",langNumb[lang], zozS->count); fprintf(fOut,"
%s %li %s\n",langSSiz[lang], zozS->size, langByte[lang]); fprintf(fOut,"
\n"); fprintf(fOut,"\n

%s

\n",langEndStat[lang]); fprintf(fOut,"\n"); fprintf(fOut,"
%s %li\n",langTotMess[lang], nSprav); fprintf(fOut,"
%s %li\n",langTotAuth[lang], GetCount(zozA)); fprintf(fOut,"
%s %li\n",langTotSubj[lang], GetCount(zozS)); fprintf(fOut,"
%s %li %s\n",langTotLeng[lang], nDlzka, langByte[lang]); fprintf(fOut,"
%s %li %s\n",langAvgLeng[lang], nDlzka/nSprav, langByte[lang]); fprintf(fOut,"
\n"); fprintf(fOut,"\n
\n"); fprintf(fOut,"\n"); fprintf(fOut,"
Input file last updated: %s", ctime(&t)); fprintf(fOut,"Generated by MailListStat v%s\n",VERSION); fprintf(fOut,"
\n"); } else fprintf(fOut,"\n

No messages found. Therefore no stats can be computed!

\n"); if (mode!=2) fprintf(fOut,"\n"); // don't print HTML header/footer in html2 mode }