/*
- * irssistats version 0.61
+ * irssistats version 0.70
*
* This tool generates IRC stats based on irssi logs.
* Usage: irssistats [/path/to/file.conf]
* 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 <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
+#ifdef __WIN32__
+#define GLOBALCONF "irssistats.conf"
+#else
+#define GLOBALCONF "/etc/irssistats.conf"
#include <regex.h>
+#endif
/* Config */
#define BASEUSERS 1000
#define MINWORDLENGTH 5
/* irssistats */
-#define VERSION "0.61"
+#define VERSION "0.70"
#define URL "http://royale.zerezo.com/irssistats/"
/* Counters */
char *counters[NBCOUNTERS]={"C_SMILE","C_FROWN","C_EXCLAM","C_QUESTION","C_ME","C_TOPIC","C_MODE","C_KICK","C_KICKED","C_URL","C_JOIN","C_NICK","C_MONOLOGUE"};
/* Languages */
-#define NBLANGUAGES 10
+#define NBLANGUAGES 11
#define NBKEYS 39
char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
{
},
{ /* Dutch language */
/* contributed by Jeroen Ubbink <crasp@blackbyte.nl> */
+ /* updated by Wouter Horré <wouter@ligezin.be> */
{ "Dutch", "nl" },
{ "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statistieken voor %s door %s" },
{ "LASTDAYS", "Statistieken van de laatste dagen" },
{ "TOPHOURS", "Statistieken per uur" },
{ "TOPUSERS", "Meest actieve mensen" },
- { "OTHERS", "Er zijn nog %d niet in de top..." },
+ { "OTHERS", "Er zijn nog %d mensen die de top niet haalden..." },
{ "NBLINES", "regels" },
{ "NICK", "nick" },
{ "AVGLETTERS", "letters/lijn" },
{ "BIGNUMBERS", "Enkele grote aantallen..." },
{ "NUMBERS", "numbers" },
{ "TIME", "%d regels (%d dagen) verwerkt in %d seconden" },
- { "FOOTER", "Statistieken gegenereert door" },
+ { "FOOTER", "Statistieken gegenereerd door" },
{ "C_SMILE", "is vaak vrolijk :)" },
{ "C_FROWN", "is vaak droevig :(" },
{ "C_EXCLAM", "schreeuwt veel !" },
{ "C_JOIN", "twijfelt tussen blijven of gaan" },
{ "C_NICK", "verandert vaak van nick" },
{ "C_MONOLOGUE", "spreekt veel monologen" }
- },
+ },
{ /* Russian language */
+ /* contributed by kamikaze <kamikaze@rss.lv> */
{ "Russian", "ru" },
{ "CHARSET", "KOI8-R" },
{ "HEADER", "óÔÁÔÉÓÔÉËÁ ÄÌÑ %s ÏÔ %s" },
{ "C_JOIN", "ÎÅ ÚÎÁÅÔ - ÏÓÔÁÔØÓÑ ÉÌÉ ÕÊÔÉ" },
{ "C_NICK", "ÞÁÓÔÏ ÍÅÎÑÅÔ Ó×ÏÊ ÎÉË" },
{ "C_MONOLOGUE", "éÓÐÏÌØÚÕÅÔ ÍÎÏÇÏ ÍÏÎÏÌÏÇÏ×" }
+ },
+ { /* Estonian language */
+ /* contributed by Martin Vool <mardicas@hot.ee> */
+ { "Estonian", "et" },
+ { "CHARSET", "ISO-8859-4" },
+ { "HEADER", "Statistika kanalile %s on koostanud %s" },
+ { "LEGEND", "Legend" },
+ { "LASTDAYS", "Viimaste päevade statistika" },
+ { "TOPHOURS", "Tunni statistika" },
+ { "TOPUSERS", "Kõige aktiivsemad inimesed" },
+ { "OTHERS", "%d inimest on rääkinud" },
+ { "NBLINES", "rida" },
+ { "NICK", "nimi" },
+ { "AVGLETTERS", "tähte/rida" },
+ { "HOURS", "kell" },
+ { "QUOTE", "suvaline teade" },
+ { "TOPUSERSTIME", "Kõige aktiivsemad inimesed päeva aja järgi" },
+ { "RANDTOPICS", "Mõned topicud" },
+ { "CHANGEDBY", "muutis" },
+ { "NEWTOPIC", "topicud" },
+ { "RANDURLS", "Mõned aadressid" },
+ { "POSTEDBY", "postitas" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Enim kasutatud sõnad" },
+ { "WORD", "sõna" },
+ { "OCCURRENCES", "sagedus" },
+ { "BIGNUMBERS", "Mõned suured numbrid" },
+ { "NUMBERS", "iseloom" },
+ { "TIME", "%d rida (%d päeva) on möödunud %d sekundit" },
+ { "FOOTER", "Statistika on koostanud" },
+ { "C_SMILE", "on tihti õnnelik :)" },
+ { "C_FROWN", "on tihti kurb :(" },
+ { "C_EXCLAM", "põrnitseb palju" },
+ { "C_QUESTION", "küsib palju küsimusi" },
+ { "C_ME", "/me manjakk" },
+ { "C_TOPIC", "vahetab tihti topicut" },
+ { "C_MODE", "vahetab tihti modesid" },
+ { "C_KICK", "kickib palju" },
+ { "C_KICKED", "saab tihti kicke" },
+ { "C_URL", "reklaamib palju" },
+ { "C_JOIN", "sõelub sisse ja välja" },
+ { "C_NICK", "vahetab pidevalt nime" },
+ { "C_MONOLOGUE", "räägib palju monolooge" }
}
};
int debug=1; /* 0 = none ; 1 = normal ; 2 = verbose */
char channel[MAXLINELENGTH]="set_channel_in_config_file";
char maintainer[MAXLINELENGTH]="set_maintainer_in_config_file";
-char theme[MAXLINELENGTH]="default,blue,dark,grayscale,namour,pisg,zeduel,zerezo";
+char theme[MAXLINELENGTH]="default,biseau,blue,dark,damier,grayscale,namour,niflheim,pisg,zeduel,zerezo";
int refresh_time=0; /* 0 = disabled */
int w3c_link=1; /* 0 = disabled */
+int logo=1; /* 0 = disabled */
char header[MAXLINELENGTH]="none";
char footer[MAXLINELENGTH]="none";
int totallines=0;
int top_words=1; /* 0 = disabled */
int ranking=0; /* 0 = lines ; 1 = words ; 2 = letters */
int quarter=0; /* 1 = enabled */
+int photo_size=60;
struct user
{
int hours[4];
char quote[MAXQUOTELENGTH+1];
int counters[NBCOUNTERS];
+ char *photo;
int temp;
} *users;
int nbusers=0;
strcpy(users[i].quote,users[i-1].quote);
for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=users[i-1].counters[j];
users[i].temp=users[i-1].temp;
+ users[i].photo=users[i-1].photo;
}
strcpy(users[start].nick,nick);
users[start].lines=0;
users[start].quote[0]='\0';
for (j=0;j<NBCOUNTERS;j++) users[start].counters[j]=0;
users[start].temp=0;
+ users[start].photo=NULL;
}
return(start);
}
while (fgets(line,MAXLINELENGTH,fic)!=NULL)
{
/* remove \n */
- for (i=0;line[i]!=0;i++);
- if (i>=MAXLINELENGTH-1) { fprintf(stderr,"line %d is too long\n",totallines); exit(1); }
+ for (i=0;line[i]!=0 && i<MAXLINELENGTH-1;i++);
+ if (i>=MAXLINELENGTH-1) {
+ if(debug){
+ fprintf(stderr,"line %d is too long, skipping\n",totallines+1);
+ }
+ continue;
+ }
+ if (i<8) {
+ if(debug) {
+ fprintf(stderr, "line %d is too short to be valid, skipping\n",totallines+1);
+ }
+ continue;
+ }
line[i-1]='\0';
pos=0;
totallines++;
}
else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
{
- for (i=10;line[i]!=' ';i++);
+ for (i=10;line[i]!=' ' && i <= 10 + MAXNICKLENGTH;i++);
+ if(i > 10 + MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
line[i]='\0';
nick=&line[10];
message=&line[i+1];
hour=atoi(line);
if (line[7]=='*') /* 00:00 * Nick the message */
{
- for (i=9;line[i]!=' ';i++);
+ for (i=9;line[i]!=' ' && i <= 9 + MAXNICKLENGTH;i++);
+ if(i > 9 + MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
nick=&line[9];
message=&line[i+1];
}
else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
/* 00:00 <>>?Nick<<> the personal message */
{
- for (i=10;line[i]!='<';i++);
+ for (i=10;line[i]!='<' && i <= 10 + MAXNICKLENGTH;i++);
+ if(i > 10 + MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
nick=&line[10];
if (line[9]=='>') nick++;
message=&line[i+5];
nickstart = 7;
}
- for (i=nickstart;line[i]!='>';i++);
+ for (i=nickstart;line[i]!='>' && i <= nickstart + MAXNICKLENGTH;i++);
+ if(i > nickstart + MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
nick=&line[nickstart];
message=&line[i+2];
}
if (debug) printf(" done\n");
}
+#ifndef __WIN32__
void parse_nick(char *nickfile)
{
FILE *fic;
for (j=0;j<4;j++) users[i].hours[j]=-1;
for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
}
+#endif
+
+void parse_photo(char *photofile)
+{
+ FILE *fic;
+ char line[MAXLINELENGTH];
+ int user;
+
+ if ((fic=fopen(photofile,"rt"))==NULL) { fprintf(stderr,"can't open photo file \"%s\"\n",photofile); exit(1); }
+ while (fscanf(fic,"%s",line)==1)
+ {
+ user=dichotomic(line);
+ fscanf(fic,"%s",line);
+ users[user].photo=malloc(strlen(line)+1);
+ strcpy(users[user].photo,line);
+ }
+ fclose(fic);
+}
void gen_xhtml(char *xhtmlfile)
{
int user,max,temp;
char line[MAXLINELENGTH];
char *subtheme;
+ int photos=0;
+
+ for (i=0;i<nbusers;i++) if (users[i].photo!=NULL) photos=1;
if ((fic=fopen(xhtmlfile,"wt"))==NULL) { fprintf(stderr,"can't open xhtml file \"%s\"\n",xhtmlfile); exit(1); }
switch (ranking)
{
case 0:
- fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th></tr>\n",L("NICK"),L("NBLINES"),L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
+ fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th>\n",L("NICK"),L("NBLINES"),L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
break;
default:
/* "letters" and "words" ranking are not yet translated so we use the generic word "rank" ... */
- fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th></tr>\n",L("NICK"),"rank",L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
+ fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th><th>%s</th><th colspan=\"2\">%s</th><th>%s</th>\n",L("NICK"),"rank",L("HOURS"),L("AVGLETTERS"),L("QUOTE"));
break;
}
+ if (photos) fprintf(fic,"<th></th>");
+ fprintf(fic,"</tr>");
for (i=1;i<=NBUSERS;i++)
{
user=-1;
for (j=0;j<4;j++) if (users[user].hours[j]!=0) fprintf(fic,"<div class=\"h%d\" style=\"width:%dpx\"></div>",j+1,100*users[user].hours[j]/users[user].lines);
fprintf(fic,"</td><td>%d</td><td><div class=\"hm\" style=\"width:%dpx\"></div></td><td>\"",users[user].lines!=0?users[user].letters/users[user].lines:0,users[user].lines!=0?users[user].letters/users[user].lines:0);
printhtml(fic,users[user].quote);
- fprintf(fic,"\"</td></tr>\n");
+ fprintf(fic,"\"</td>");
+ if (photos && users[user].photo!=NULL)
+ {
+ if (photo_size)
+ fprintf(fic,"<td class=\"tdphoto\"><a href=\"%s\"><img src=\"%s\" class=\"imgphoto\" width=\"%d\" height=\"%d\" alt=\"\" style=\"border: 0\" /></a></td>",users[user].photo,users[user].photo,photo_size,photo_size);
+ else
+ fprintf(fic,"<td class=\"tdphoto\"><img src=\"%s\" class=\"imgphoto\" alt=\"\" /></td>",users[user].photo,users[user].photo);
+ }
+ fprintf(fic,"</tr>\n");
users[user].lines=-1;
users[user].words=-1;
users[user].letters=-1;
fprintf(fic,"<p>\n<a href=\"http://validator.w3.org/check/referer\"><img src=\"valid-xhtml10.png\" height=\"31\" width=\"88\" alt=\"Valid XHTML 1.0!\" /></a>\n");
fprintf(fic,"<a href=\"http://jigsaw.w3.org/css-validator/check/referer\"><img src=\"valid-css.png\" height=\"31\" width=\"88\" alt=\"Valid CSS!\" /></a>\n</p>\n");
}
- fprintf(fic,"</div>\n\n</div>");
- if (strcmp("none",header)==0)
+ fprintf(fic,"</div>\n\n");
+
+ /* logo*/
+ if (logo) fprintf(fic,"<div class=\"logo\"></div>\n\n");
+
+ /* end */
+ if (strcmp("none",footer)==0)
{
- fprintf(fic,"\n\n</body>\n\n</html>\n");
+ fprintf(fic,"</div>\n\n</body>\n\n</html>\n");
}
else
{
void parse_config(char *configfile)
{
+ void expand(char *path)
+ {
+ char temp[MAXLINELENGTH];
+ if (*path=='~')
+ {
+ snprintf(temp,MAXLINELENGTH-1,"%s%s",getenv("HOME"),path+1);
+ temp[MAXLINELENGTH-1]='\0';
+ strcpy(path,temp);
+ }
+ }
+
FILE *fic;
char line[MAXLINELENGTH];
char keyword[MAXLINELENGTH];
}
else
{
- sprintf(line,"%s/.irssistats",getenv("HOME"));
+ snprintf(line,MAXLINELENGTH-1,"%s/.irssistats",getenv("HOME"));
+ line[MAXLINELENGTH-1]='\0';
if ((fic=fopen(line,"rt"))==NULL)
- if ((fic=fopen("/etc/irssistats.conf","rt"))==NULL)
+ if ((fic=fopen(GLOBALCONF,"rt"))==NULL)
{
- fprintf(stderr,"can't find config file : \"%s\" nor \"/etc/irssistats.conf\"\n",line);
+ fprintf(stderr,"can't find config file : \"%s\" nor \"" GLOBALCONF "\"\n",line);
fprintf(stderr,"please give the path to the config file in argument\n");
exit(1);
}
}
else
+ if (strcmp("photo_size",keyword)==0)
+ {
+ photo_size=atoi(value);
+ if (debug==2) fprintf(stderr,"setting photo_size to \"%d\"\n",photo_size);
+ }
+ else
+
if (strcmp("w3c_link",keyword)==0)
{
if (debug==2) fprintf(stderr,"setting w3c_link to \"%s\"\n",value);
}
else
+ if (strcmp("logo",keyword)==0)
+ {
+ if (debug==2) fprintf(stderr,"setting logo to \"%s\"\n",value);
+ if (strcmp("no",value)==0) logo=0;
+ else if (strcmp("yes",value)==0) logo=1;
+ else { fprintf(stderr,"unknown value for \"logo\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+ }
+ else
+
if (strcmp("header",keyword)==0)
{
+ expand(value);
if (debug==2) fprintf(stderr,"setting header to \"%s\"\n",value);
strcpy(header,value);
}
if (strcmp("footer",keyword)==0)
{
+ expand(value);
if (debug==2) fprintf(stderr,"setting footer to \"%s\"\n",value);
strcpy(footer,value);
}
if (strcmp("input",keyword)==0)
{
+ expand(value);
if (debug==2) fprintf(stderr,"parsing log file \"%s\"\n",value);
parse_log(value);
}
if (strcmp("nickfile",keyword)==0)
{
+ expand(value);
if (debug==2) fprintf(stderr,"nick alias using file \"%s\"\n",value);
+#ifdef __WIN32__
+ fprintf(stderr,"no support for nickfile in WIN32 version\n");
+#else
parse_nick(value);
+#endif
+ }
+ else
+
+ if (strcmp("photofile",keyword)==0)
+ {
+ expand(value);
+ if (debug==2) fprintf(stderr,"parsing photo file \"%s\"\n",value);
+ parse_photo(value);
}
else
if (strcmp("output",keyword)==0)
{
+ expand(value);
if (debug==2) fprintf(stderr,"generating xhtml file \"%s\"\n",value);
bestwords(words,0);
gen_xhtml(value);
for (i=0;i<NBWORDS;i++) topwords[i].nb=0;
totallines=0;
debut=time(NULL);
+ for (i=0;i<nbusers;i++)
+ {
+ free(users[i].photo);
+ users[i].photo=NULL;
+ }
}
else