#include <string.h>
/* Config */
-#define MAXUSERS 2000
+#define MAXUSERS 5000
#define MAXNICKLENGTH 50
#define MAXLINELENGTH 2000
#define MAXQUOTELENGTH 100
#define NBUSERS 50
+#define NBUSERSTIME 10
#define NBURLS 5
#define NBTOPICS 5
#define NBWORDS 20
#define MINWORDLENGTH 5
/* irssistats */
-#define VERSION "0.2"
+#define VERSION "0.3"
#define URL "http://royale.zerezo.com/programmation/irssistats/"
+/* Counters */
+#define D_SMILE 0
+#define D_FROWN 1
+#define D_EXCLAM 2
+#define D_QUESTION 3
+#define D_ME 4
+#define D_TOPIC 5
+#define D_MODE 6
+#define D_KICK 7
+#define D_KICKED 8
+#define D_URL 9
+#define D_JOIN 10
+#define D_NICK 11
+#define D_MONOLOGUE 12
+#define NBCOUNTERS 13
+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 2
-#define NBKEYS 22
+#define NBKEYS 38
char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
{
{ /* English language */
- { "English", "en" },
- { "HEADER", "Statistics for #%s by %s" },
- { "LEGEND", "Legend" },
- { "LASTDAYS", "Lastdays statistics" },
- { "TOPHOURS", "Hourly statistics" },
- { "TOPUSERS", "Most active people" },
- { "OTHERS", "There are %d left not ranked..." },
- { "NBLINES", "lines" },
- { "NICK", "nick" },
- { "AVGLETTERS", "letters/lines" },
- { "HOURS", "hours" },
- { "QUOTE", "random message" },
- { "RANDTOPICS", "Some topics" },
- { "CHANGEDBY", "changed by" },
- { "NEWTOPIC", "new topic" },
- { "RANDURLS", "Some URLs" },
- { "POSTEDBY", "posted by" },
- { "POSTEDURL", "URL" },
- { "TOPWORDS", "Most used words" },
- { "WORD", "word" },
- { "OCCURRENCES", "occurrences" },
- { "TIME", "%d lines parsed in %d seconds" },
- { "FOOTER", "Statistics generated by" }
+ { "English", "en" },
+ { "HEADER", "Statistics for #%s by %s" },
+ { "LEGEND", "Legend" },
+ { "LASTDAYS", "Lastdays statistics" },
+ { "TOPHOURS", "Hourly statistics" },
+ { "TOPUSERS", "Most active people" },
+ { "OTHERS", "There are %d left not ranked..." },
+ { "NBLINES", "lines" },
+ { "NICK", "nick" },
+ { "AVGLETTERS", "letters/lines" },
+ { "HOURS", "hours" },
+ { "QUOTE", "random message" },
+ { "TOPUSERSTIME", "Most active people by time of day" },
+ { "RANDTOPICS", "Some topics" },
+ { "CHANGEDBY", "changed by" },
+ { "NEWTOPIC", "new topic" },
+ { "RANDURLS", "Some URLs" },
+ { "POSTEDBY", "posted by" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Most used words" },
+ { "WORD", "word" },
+ { "OCCURRENCES", "occurrences" },
+ { "BIGNUMBERS", "Some big numbers..." },
+ { "NUMBERS", "numbers" },
+ { "TIME", "%d lines parsed in %d seconds" },
+ { "FOOTER", "Statistics generated by" },
+ { "C_SMILE", "is often happy :)" },
+ { "C_FROWN", "is often sad :(" },
+ { "C_EXCLAM", "yells a lot !" },
+ { "C_QUESTION", "asks a lot of questions ?" },
+ { "C_ME", "likes /me command" },
+ { "C_TOPIC", "often changes the topic" },
+ { "C_MODE", "often changes the modes" },
+ { "C_KICK", "likes to /kick" },
+ { "C_KICKED", "is often kicked" },
+ { "C_URL", "posts many URLs" },
+ { "C_JOIN", "doesn't know wether to stay or quit" },
+ { "C_NICK", "often changes his nick" },
+ { "C_MONOLOGUE", "speaks a lot of monologues" }
},
{ /* French language */
- { "Français", "fr" },
- { "HEADER", "Statistiques de #%s par %s" },
- { "LEGEND", "Légende" },
- { "LASTDAYS", "Statistiques des derniers jours" },
- { "TOPHOURS", "Statistiques horaires" },
- { "TOPUSERS", "Personnes les plus actives" },
- { "OTHERS", "Il reste %d personnes non classées..." },
- { "NBLINES", "lignes" },
- { "NICK", "nick" },
- { "AVGLETTERS", "lettres/lignes" },
- { "HOURS", "heures" },
- { "QUOTE", "message aléatoire" },
- { "RANDTOPICS", "Quelques topics" },
- { "CHANGEDBY", "changé par" },
- { "NEWTOPIC", "nouveau topic" },
- { "RANDURLS", "Quelques URLs" },
- { "POSTEDBY", "postée par" },
- { "POSTEDURL", "URL" },
- { "TOPWORDS", "Mots les plus utilisés" },
- { "WORD", "mot" },
- { "OCCURRENCES", "occurrences" },
- { "TIME", "%d lignes traitées en %d secondes" },
- { "FOOTER", "Statistiques générées par" }
+ { "Français", "fr" },
+ { "HEADER", "Statistiques de #%s par %s" },
+ { "LEGEND", "Légende" },
+ { "LASTDAYS", "Statistiques des derniers jours" },
+ { "TOPHOURS", "Statistiques horaires" },
+ { "TOPUSERS", "Personnes les plus actives" },
+ { "OTHERS", "Il reste %d personnes non classées..." },
+ { "NBLINES", "lignes" },
+ { "NICK", "nick" },
+ { "AVGLETTERS", "lettres/lignes" },
+ { "HOURS", "heures" },
+ { "QUOTE", "message aléatoire" },
+ { "TOPUSERSTIME", "Personnes les plus actives par période de la journée" },
+ { "RANDTOPICS", "Quelques topics" },
+ { "CHANGEDBY", "changé par" },
+ { "NEWTOPIC", "nouveau topic" },
+ { "RANDURLS", "Quelques URLs" },
+ { "POSTEDBY", "postée par" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Mots les plus utilisés" },
+ { "WORD", "mot" },
+ { "OCCURRENCES", "occurrences" },
+ { "BIGNUMBERS", "Quelques grands nombres..." },
+ { "NUMBERS", "nombres" },
+ { "TIME", "%d lignes traitées en %d secondes" },
+ { "FOOTER", "Statistiques générées par" },
+ { "C_SMILE", "est souvent heureux :)" },
+ { "C_FROWN", "est souvent triste :(" },
+ { "C_EXCLAM", "hurle beaucoup !" },
+ { "C_QUESTION", "pose beaucoup de questions ?" },
+ { "C_ME", "aime la commande /me" },
+ { "C_TOPIC", "change souvent le topic" },
+ { "C_MODE", "change souvent les modes" },
+ { "C_KICK", "aime la commande /kick" },
+ { "C_KICKED", "est souvent kické" },
+ { "C_URL", "poste beaucoup d'URLs" },
+ { "C_JOIN", "ne sait pas s'il doit rester ou partir" },
+ { "C_NICK", "change souvent de nick" },
+ { "C_MONOLOGUE", "parle beaucoup de monologues" }
}
};
}
/* Themes */
-#define NBTHEMES 3
+#define NBTHEMES 5
#define NBCOLORS 9
char *colors[NBTHEMES][NBCOLORS+1][2]= /* first key used for theme name/description and abbreviation */
{
{ "TITLE2", "#84DB8C" },
{ "BGTABLE", "#085D10" },
{ "BGTITLE", "#0B810B" }
+ },
+ { /* tit-namour theme */
+ { "Purple and Pink", "namour" },
+ { "BGCOLOR", "#9933CC" },
+ { "TEXT", "#DDAAFF" },
+ { "LINK", "#CC99FF" },
+ { "VLINK", "#999999" },
+ { "ALINK", "#FFC8C8" },
+ { "TITLE1", "#FFC8C8" },
+ { "TITLE2", "#FFC8C8" },
+ { "BGTABLE", "#7711AA" },
+ { "BGTITLE", "#550088" }
+ },
+ { /* zeDuel theme */
+ { "Orange theme...", "zeduel" },
+ { "BGCOLOR", "#FFFFFF" },
+ { "TEXT", "#000000" },
+ { "LINK", "#FF7700" },
+ { "VLINK", "#C05A00" },
+ { "ALINK", "#FF9A41" },
+ { "TITLE1", "#C05A00" },
+ { "TITLE2", "#FF7700" },
+ { "BGTABLE", "#FFEEEE" },
+ { "BGTITLE", "#FF7700" }
}
};
int lines;
int letters;
int hours[4];
- char quote[MAXLINELENGTH];
+ char quote[MAXQUOTELENGTH+1];
+ int counters[NBCOUNTERS];
} users[MAXUSERS];
int nbusers=0;
{
char nick[MAXNICKLENGTH];
char url[MAXLINELENGTH];
+ char shorturl[MAXQUOTELENGTH+1];
} urls[5];
int nburls=0;
struct
{
char nick[MAXNICKLENGTH];
- char topic[MAXLINELENGTH];
+ char topic[MAXQUOTELENGTH+1];
} topics[5];
int nbtopics=0;
tempword[cur]='\0';
}
-void unhtml(char *string) /* replace < and > by { and } */
+void printhtml(char *string) /* replace < and > by < and > */
{
while (*string!='\0')
{
- if (*string=='<') *string='{';
- if (*string=='>') *string='}';
+ switch (*string)
+ {
+ case '<':printf("<"); break;
+ case '>':printf(">"); break;
+ case '&':printf("&"); break;
+ default:printf("%c",*string); break;
+ }
string++;
}
return;
users[i].letters=users[i-1].letters;
for (j=0;j<4;j++) users[i].hours[j]=users[i-1].hours[j];
strcpy(users[i].quote,users[i-1].quote);
+ for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=users[i-1].counters[j];
}
strcpy(users[start].nick,nick);
users[start].lines=0;
users[start].letters=0;
for (j=0;j<4;j++) users[start].hours[j]=0;
users[start].quote[0]='\0';
+ for (j=0;j<NBCOUNTERS;j++) users[start].counters[j]=0;
}
return(start);
}
int main(int argc,char *argv[])
{
- int i,j;
+ int i,j,k;
int max,user,hour;
+ int mononick,monolines;
time_t debut;
int totallines=0;
int pos=0;
char line[MAXLINELENGTH];
/*** INIT ***/
+
if (argc!=5)
{
fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html\n\n");
+ fprintf(stderr,"Version :\nirssistats %s\n\n",VERSION);
fprintf(stderr,"Supported languages :\n");
for (i=0;i<NBLANGUAGES;i++) fprintf(stderr,"%s = %s\n",keys[i][0][1],keys[i][0][0]);
fprintf(stderr,"\nSupported themes :\n");
if (pos>=MAXLINELENGTH) { fprintf(stderr,"line too long\n"); exit(1); }
if (c=='\n')
{
+ line[pos-1]='\0';
totallines++;
if (totallines%10000==0) { fprintf(stderr,"."); fflush(stdout); }
if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
for (j=0;j<4;j++) lastdays[0].hours[j]=0;
days++;
}
- else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick changed the topic of #channel to: new topic */
+ else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by Nick(, Nick2, Nick3...) */
+ {
+ for (i=15;(line[i]!=']')||(line[i+1]!=' ');i++);
+ nick=&line[i+5];
+ for (i=0;(nick[i]!='\0')&&(nick[i]!=',');i++);
+ nick[i]='\0';
+ users[dichotomic(nick)].counters[D_MODE]++;
+ }
+ else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
{
for (i=10;line[i]!=' ';i++);
line[i]='\0';
nick=&line[10];
- unhtml(nick);
message=&line[i+1];
- unhtml(message);
- if (strncmp("changed the topic of",message,20)==0)
+ if (strncmp("changed the topic of",message,20)==0) /* 00:00 -!- Nick changed the topic of #channel to: new topic */
{
+ users[dichotomic(nick)].counters[D_TOPIC]++;
for (i=21;message[i]!=':';i++);
message=&message[i+2];
- line[pos-1]='\0';
nbtopics++;
if ((nbtopics<=5) || (rand()%nbtopics==0))
{
strcpy(topics[i].topic,topics[i-1].topic);
}
strcpy(topics[0].nick,nick);
- strcpy(topics[0].topic,message);
+ strncpy(topics[0].topic,message,MAXQUOTELENGTH);
}
}
+ else if (strncmp("was kicked from",message,15)==0) /* 00:00 -!- Nick was kicked from #channel by Nick [Reason] */
+ {
+ users[dichotomic(nick)].counters[D_KICKED]++;
+ for (i=16;message[i]!=' ';i++);
+ message=&message[i+4];
+ for (i=0;message[i]!=' ';i++);
+ message[i]='\0';
+ users[dichotomic(message)].counters[D_KICK]++;
+ }
+ else if (strncmp("is now known as",message,15)==0) /* 00:00 -!- Nick is now known as Nick */
+ users[dichotomic(nick)].counters[D_NICK]++;
+ else if (message[0]=='[') /* 00:00 -!- Nick [user@host] something... */
+ {
+ for (i=0;message[i]!=']';i++);
+ message=&message[i+2];
+ if (strncmp("has joined",message,10)==0) /* 00:00 -!- Nick [user@host] has joined #channel */
+ users[dichotomic(nick)].counters[D_JOIN]++;
+ else if (strncmp("has quit",message,8)==0); /* 00:00 -!- Nick [user@host] has quit [Reason] */
+ else if (strncmp("has left",message,8)==0); /* 00:00 -!- Nick [user@host] has left #channel [Reason] */
+ else;
+ }
}
else if ((line[6]=='<') || (line[7]=='*'))
{
message=&line[i+2];
}
line[i]='\0';
- line[pos-1]='\0';
- unhtml(nick);
- unhtml(message);
i=dichotomic(nick);
+ if (line[7]=='*') users[i].counters[D_ME]++;
+ if (i==mononick)
+ {
+ monolines++;
+ if (monolines==5) users[i].counters[D_MONOLOGUE]++;
+ }
+ else
+ {
+ mononick=i;
+ monolines=1;
+ }
+ j=strlen(message);
users[i].lines++;
- users[i].letters+=strlen(message);
+ users[i].letters+=j;
users[i].hours[hour/6]++;
lastdays[0].lines++;
lastdays[0].hours[hour/6]++;
lines++;
hours[hour]++;
+ if (message[j-1]=='?') users[i].counters[D_QUESTION]++;
+ else if (message[j-1]=='!') users[i].counters[D_EXCLAM]++;
+ else if ((message[j-3]==' ')&&(message[j-2]==':'))
+ {
+ if (message[j-1]==')') users[i].counters[D_SMILE]++;
+ else if (message[j-1]=='(') users[i].counters[D_FROWN]++;
+ }
if (rand()%users[i].lines==0) strncpy(users[i].quote,message,MAXQUOTELENGTH);
if (strncmp("http://",message,7)==0)
{
+ users[i].counters[D_URL]++;
for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
message[i]='\0';
nburls++;
{
strcpy(urls[i].nick,urls[i-1].nick);
strcpy(urls[i].url,urls[i-1].url);
+ strcpy(urls[i].shorturl,urls[i-1].shorturl);
}
strcpy(urls[0].nick,nick);
strcpy(urls[0].url,message);
+ strncpy(urls[0].shorturl,message,MAXQUOTELENGTH);
}
}
findwords(message);
/* legend */
printf("<font color=\"%s\"><h3>%s</h3></font>\n<table bgcolor=%s>\n<tr>\n",T("TITLE2"),L("LEGEND"),T("BGTABLE"));
- for (i=0;i<4;i++) printf("<td><img src=\"h%d.png\" width=\"40\" height=\"15\"></td><td> : %s %d-%d </td><td width=\"10\"></td>\n",i+1,L("HOURS"),i*6,i*6+5);
+ for (i=0;i<4;i++) printf("<td><img src=\"h%d.png\" width=\"40\" height=\"15\"></td><td> : %s %d-%d</td><td width=\"10\"></td>\n",i+1,L("HOURS"),i*6,i*6+5);
printf("</tr>\n</table>\n<br><br>\n\n");
/* last days */
{
printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\">",T("BGTABLE"),i,T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].lines,T("BGTABLE"));
for (j=0;j<4;j++) if (users[user].hours[j]!=0) printf("<img src=\"h%d.png\" width=\"%d\" height=\"15\">",j+1,100*users[user].hours[j]/users[user].lines);
- printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"%s\"</td></tr>\n",T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].quote);
+ printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"",T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"));
+ printhtml(users[user].quote);
+ printf("\"</td></tr>\n");
users[user].lines=-1;
}
}
printf("<br>\n");
}
printf("<br><br>\n\n");
+
+ /* top users by time */
+ printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPUSERSTIME"));
+ printf("<table>\n<tr><td></td>");
+ for (i=0;i<4;i++) printf("<td bgcolor=\"%s\" colspan=\"2\">%s %d-%d</td>",T("BGTITLE"),L("HOURS"),i*6,i*6+5);
+ printf("</tr>\n");
+ for (i=1;i<=NBUSERSTIME;i++)
+ {
+ printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td>",T("BGTABLE"),i);
+ for (j=0;j<4;j++)
+ {
+ user=-1;
+ max=-1;
+ for (k=0;k<nbusers;k++) if (users[k].hours[j]>max) max=users[user=k].hours[j];
+ if (user!=-1)
+ {
+ printf("<td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td>",T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].hours[j]);
+ users[user].hours[j]=-1;
+ }
+ else printf("<td></td><td></td>");
+ }
+ printf("</tr>\n");
+ }
+ printf("</table>\n<br><br>\n\n");
/* random topics */
printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDTOPICS"));
printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("CHANGEDBY"),T("BGTITLE"),L("NEWTOPIC"));
for (i=nbtopics<NBTOPICS?nbtopics-1:NBTOPICS-1;i>=0;i--)
- printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"%s\"</td></tr>\n",T("BGTABLE"),topics[i].nick,T("BGTABLE"),topics[i].topic);
+ {
+ printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"",T("BGTABLE"),topics[i].nick,T("BGTABLE"));
+ printhtml(topics[i].topic);
+ printf("\"</td></tr>\n");
+ }
printf("</table>\n<br><br>\n\n");
/* random urls */
printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDURLS"));
printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("POSTEDBY"),T("BGTITLE"),L("POSTEDURL"));
for (i=nburls<NBURLS?nburls-1:NBURLS-1;i>=0;i--)
- printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"<a href=\"%s\">%s</a>\"</td></tr>\n",T("BGTABLE"),urls[i].nick,T("BGTABLE"),urls[i].url,urls[i].url);
+ {
+ printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"<a href=\"%s\">",T("BGTABLE"),urls[i].nick,T("BGTABLE"),urls[i].url);
+ printhtml(urls[i].shorturl);
+ printf("</a>\"</td></tr>\n");
+ }
printf("</table>\n<br><br>\n\n");
/* top words */
for (i=0;i<NBWORDS;i++)
if (topwords[i].nb!=0) printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">\"%s\"</td><td bgcolor=\"%s\">%d</td></tr>\n",T("BGTABLE"),i+1,T("BGTABLE"),topwords[i].word,T("BGTABLE"),topwords[i].nb);
printf("</table>\n<br><br>\n\n");
+
+ /* big numbers */
+ printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("BIGNUMBERS"));
+ printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NUMBERS"),T("BGTITLE"),L("NBLINES"));
+ for (i=0;i<NBCOUNTERS;i++)
+ {
+ user=-1;
+ max=0;
+ for (j=0;j<nbusers;j++) if (users[j].counters[i]>max) max=users[user=j].counters[i];
+ if (user!=-1) printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td></tr>",T("BGTABLE"),users[user].nick,T("BGTABLE"),L(counters[i]),T("BGTABLE"),users[user].counters[i]);
+ }
+ printf("</table>\n<br><br>\n\n");
/* footer */
printf(L("TIME"),totallines,(int)(time(NULL)-debut));