version 0.41
[irssistats] / irssistats.c
index c528da3..1ddd0cc 100644 (file)
@@ -1,9 +1,10 @@
-/* Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html */
+/* Usage: cat /path/to/file.log | ./irssistats \#channel maintainer language theme [nickfile] > /path/to/file.html */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <string.h>
+#include <regex.h>
 
 /* Config */
 #define MAXUSERS 5000
@@ -18,7 +19,7 @@
 #define MINWORDLENGTH 5
 
 /* irssistats */
-#define VERSION "0.3"
+#define VERSION "0.41"
 #define URL "http://royale.zerezo.com/programmation/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 2
+#define NBLANGUAGES 5
 #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" },
+    { "HEADER",       "Statistics for %s by %s" },
     { "LEGEND",       "Legend" },
     { "LASTDAYS",     "Lastdays statistics" },
     { "TOPHOURS",     "Hourly statistics" },
@@ -68,7 +69,7 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "OCCURRENCES",  "occurrences" },
     { "BIGNUMBERS",   "Some big numbers..." },
     { "NUMBERS",      "numbers" },
-    { "TIME",         "%d lines parsed in %d seconds" },
+    { "TIME",         "%d lines (%d days) parsed in %d seconds" },
     { "FOOTER",       "Statistics generated by" },
     { "C_SMILE",      "is often happy :)" },
     { "C_FROWN",      "is often sad :(" },
@@ -86,7 +87,7 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
   },
   { /* French language */
     { "Français",     "fr" },
-    { "HEADER",       "Statistiques de #%s par %s" },
+    { "HEADER",       "Statistiques de %s par %s" },
     { "LEGEND",       "L&eacute;gende" },
     { "LASTDAYS",     "Statistiques des derniers jours" },
     { "TOPHOURS",     "Statistiques horaires" },
@@ -109,7 +110,7 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "OCCURRENCES",  "occurrences" },
     { "BIGNUMBERS",   "Quelques grands nombres..." },
     { "NUMBERS",      "nombres" },
-    { "TIME",         "%d lignes trait&eacute;es en %d secondes" },
+    { "TIME",         "%d lignes (%d jours) trait&eacute;es en %d secondes" },
     { "FOOTER",       "Statistiques g&eacute;n&eacute;r&eacute;es par" },
     { "C_SMILE",      "est souvent heureux :)" },
     { "C_FROWN",      "est souvent triste :(" },
@@ -124,6 +125,132 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "C_JOIN",       "ne sait pas s'il doit rester ou partir" },
     { "C_NICK",       "change souvent de nick" },
     { "C_MONOLOGUE",  "parle beaucoup de monologues" }
+  },
+  { /* German language */
+    /* contributed by Valentin Gelhorn <valentin.gelhorn@web.de> */
+    { "German",       "de" },
+    { "HEADER",       "Statistiken f&uuml;r %s von %s" },
+    { "LEGEND",       "Legende" },
+    { "LASTDAYS",     "Statistik der letzten Tage" },
+    { "TOPHOURS",     "St&uuml;ndliche Statistik" },
+    { "TOPUSERS",     "Die aktivsten Personen" },
+    { "OTHERS",       "Es bleiben noch %d uneingetragene" },
+    { "NBLINES",      "Zeilen" },
+    { "NICK",         "Nick" },
+    { "AVGLETTERS",   "Buchstaben/Zeile" },
+    { "HOURS",        "Stunden" },
+    { "QUOTE",        "Zuf&auml;llig ausgewaehlte Zitate" },
+    { "TOPUSERSTIME", "Die aktivsten Personen zur bestimmten Tageszeit" },
+    { "RANDTOPICS",   "Ein paar Topics" },
+    { "CHANGEDBY",    "Gesetzt von" },
+    { "NEWTOPIC",     "Neues topic" },
+    { "RANDURLS",     "Ein paar URLs" },
+    { "POSTEDBY",     "Geschrieben von" },
+    { "POSTEDURL",    "URL" },
+    { "TOPWORDS",     "Am h&auml;ufigsten benutze W&ouml;rter" },
+    { "WORD",         "Wort" },
+    { "OCCURRENCES",  "Vorkommen" },
+    { "BIGNUMBERS",   "Ein paar grosse Zahlen" },
+    { "NUMBERS",      "Zahlen" },
+    { "TIME",         "%d Zeilen (%d Tage) analysiert in %d Sekunden" },
+    { "FOOTER",       "Statistiken wurden erstellt von" },
+    { "C_SMILE",      "ist oft gl&uuml;klich :)" },
+    { "C_FROWN",      "ist oft traurig :(" },
+    { "C_EXCLAM",     "schreit oft !" },
+    { "C_QUESTION",   "stellt viele Fragen ?" },
+    { "C_ME",         "mag /me'en" },
+    { "C_TOPIC",      "aendert oft das Topico" },
+    { "C_MODE",       "aendert oft die Modes" },
+    { "C_KICK",       "mag /kick'en" },
+    { "C_KICKED",     "wird oft gekickt"},
+    { "C_URL",        "schreibt viele URLs"},
+    { "C_JOIN",       "kann sich nicht entscheiden ob er bleiben oder gehen soll" },
+    { "C_NICK",       "&auml;ndert oft seinen Nick" },
+    { "C_MONOLOGUE",  "spricht oft Monologe" }
+  },
+  { /* Spanish language */
+    /* contributed by Alex <ainaker@gmx.net> */
+    { "Spanish",      "es" },
+    { "HEADER",       "Estad&iacute;sticas de %s por %s" },
+    { "LEGEND",       "Leyenda" },
+    { "LASTDAYS",     "Estad&iacute;sticas de los &uacute;ltimos d&iacute;as" },
+    { "TOPHOURS",     "Estad&iacute;sticas por horas" },
+    { "TOPUSERS",     "Los que m&aacute;s escriben" },
+    { "OTHERS",       "Hay %d m&aacute;s que no llegaron..." },
+    { "NBLINES",      "l&iacute;neas" },
+    { "NICK",         "nick" },
+    { "AVGLETTERS",   "letras por l&iacute;nea" },
+    { "HOURS",        "horas" },
+    { "QUOTE",        "Frase aleatoria" },
+    { "TOPUSERSTIME", "Los que m&aacute;s escriben seg&uacute;n la hora" },
+    { "RANDTOPICS",   "Algunos topics" },
+    { "CHANGEDBY",    "Puestos por" },
+    { "NEWTOPIC",     "topic" },
+    { "RANDURLS",     "Algunas URLs" },
+    { "POSTEDBY",     "puestas por" },
+    { "POSTEDURL",    "URL" },
+    { "TOPWORDS",     "Palabras m&aacute;s usadas" },
+    { "WORD",         "Palabra" },
+    { "OCCURRENCES",  "Frecuencia" },
+    { "BIGNUMBERS",   "Algunos datos..." },
+    { "NUMBERS",      "N&uacute;mero de veces" },
+    { "TIME",         "%d lineas (%d d&iacute;as) procesadas en %d segundos" },
+    { "FOOTER",       "Estad&iacute;sticas generadas por" },
+    { "C_SMILE",      "Suele estar fel&iacute;z :)" },
+    { "C_FROWN",      "Suele estar triste :(" },
+    { "C_EXCLAM",     "Grita mucho !" },
+    { "C_QUESTION",   "Hace muchas preguntas ?" },
+    { "C_ME",         "Abusa del comando /me" },
+    { "C_TOPIC",      "Suele cambiar el topic" },
+    { "C_MODE",       "Cambia a veces los modos del canal" },
+    { "C_KICK",       "Le gusta patear" },
+    { "C_KICKED",     "Es pateado con frecuencia" },
+    { "C_URL",        "Pone muchas URLs" },
+    { "C_JOIN",       "No sabe si irse o quedarse" },
+    { "C_NICK",       "Cambia mucho de nick" },
+    { "C_MONOLOGUE",  "Habla solo" }
+  },
+  { /* Polish language */
+    /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
+    { "Polish",       "pl" },
+    { "HEADER",       "Statystyki dla %s przez %s" },
+    { "LEGEND",       "Legenda" },
+    { "LASTDAYS",     "Statystyki z ostatnich dni" },
+    { "TOPHOURS",     "Statystyki godzinne" },
+    { "TOPUSERS",     "Najaktywniejsi ludzie" },
+    { "OTHERS",       "Zostalo jeszcze %d nie sklasyfikowanych..." },
+    { "NBLINES",      "linie" },
+    { "NICK",         "nick" },
+    { "AVGLETTERS",   "litery/linie" },
+    { "HOURS",        "godziny" },
+    { "QUOTE",        "przypadkowa wiadomosc" },
+    { "TOPUSERSTIME", "Najaktywniejsi ludzie wedlug czasu dnia" },
+    { "RANDTOPICS",   "Pare tematow" },
+    { "CHANGEDBY",    "zmienione przez" },
+    { "NEWTOPIC",     "nowy temat" },
+    { "RANDURLS",     "Pare URL-i" },
+    { "POSTEDBY",     "wyslane przez" },
+    { "POSTEDURL",    "URL" },
+    { "TOPWORDS",     "Najczestsze slowa" },
+    { "WORD",         "slowo" },
+    { "OCCURRENCES",  "wystapienia" },
+    { "BIGNUMBERS",   "Pare wielkich liczb..." },
+    { "NUMBERS",      "liczby" },
+    { "TIME",         "%d linii (%d dni) sparsowanych w %d sekund" },
+    { "FOOTER",       "Statystyki wygenerowane przez" },
+    { "C_SMILE",      "jest czesto szczesliwy :)" },
+    { "C_FROWN",      "jest czesto smutny :(" },
+    { "C_EXCLAM",     "duzo krzyczy !" },
+    { "C_QUESTION",   "zadaje duzo pytan ?" },
+    { "C_ME",         "lubi /mnie polecenie" },
+    { "C_TOPIC",      "czesto zmienia temat" },
+    { "C_MODE",       "czesto zmienia tryb" },
+    { "C_KICK",       "lubi /kopac" },
+    { "C_KICKED",     "czesto go wykopuja" },
+    { "C_URL",        "wysyla duzo URL-i" },
+    { "C_JOIN",       "nie wie czy zostac czy wyjsc" },
+    { "C_NICK",       "czesto zmienia swojego nicka" },
+    { "C_MONOLOGUE",  "czesto mowi monologiem" }
   }
 };
 
@@ -219,7 +346,7 @@ char *T(char *color)
 char *channel;
 char *maintainer;
 
-struct 
+struct
 {
   char nick[MAXNICKLENGTH];
   int lines;
@@ -280,17 +407,17 @@ void findwords(char *message)
     while (isletter(*message))
     {
       c=lowercase(*message)-'a';
-      if ((*pos).next[(int)c]==NULL)
+      if (pos->next[(int)c]==NULL)
       {
         tmp=malloc(sizeof(struct letter));
-        (*tmp).nb=0;
-        for (i=0;i<26;i++) (*tmp).next[i]=NULL;
-        (*pos).next[(int)c]=tmp;
+        tmp->nb=0;
+        for (i=0;i<26;i++) tmp->next[i]=NULL;
+        pos->next[(int)c]=tmp;
       }
-      pos=(*pos).next[(int)c];
+      pos=pos->next[(int)c];
       message++; 
     }
-    (*pos).nb++;
+    pos->nb++;
   }
   return;
 }
@@ -368,7 +495,7 @@ int dichotomic(char *nick)
 int main(int argc,char *argv[])
 {
   int i,j,k;
-  int max,user,hour;
+  int max,user,temp,hour;
   int mononick,monolines;
   time_t debut;
   int totallines=0;
@@ -376,12 +503,14 @@ int main(int argc,char *argv[])
   char c;
   char *nick,*message;
   char line[MAXLINELENGTH];
+  FILE *fic;
+  regex_t preg;
   
   /*** INIT ***/
   
-  if (argc!=5)
+  if ((argc<5) || (argc>6))
   {
-    fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme > /path/to/file.html\n\n");
+    fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats \\#channel maintainer language theme [nickfile] > /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]);
@@ -429,12 +558,10 @@ int main(int argc,char *argv[])
         for (j=0;j<4;j++) lastdays[0].hours[j]=0;
         days++;
       }
-      else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by Nick(, Nick2, Nick3...) */
+      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';
+        for (i=strlen(line);line[i]!=' ';i--);
+        nick=&line[i+1];
         users[dichotomic(nick)].counters[D_MODE]++;
       }
       else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
@@ -449,15 +576,11 @@ int main(int argc,char *argv[])
           for (i=21;message[i]!=':';i++);
           message=&message[i+2];
           nbtopics++;
-          if ((nbtopics<=5) || (rand()%nbtopics==0))
+          if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
           {
-            for (i=4;i>0;i--)
-            {
-              strcpy(topics[i].nick,topics[i-1].nick);
-              strcpy(topics[i].topic,topics[i-1].topic);
-            }
-            strcpy(topics[0].nick,nick);
-            strncpy(topics[0].topic,message,MAXQUOTELENGTH);
+            temp=nbtopics<=NBTOPICS?nbtopics-1:rand()%NBTOPICS;
+            strcpy(topics[temp].nick,nick);
+            strncpy(topics[temp].topic,message,MAXQUOTELENGTH);
           }
         }
         else if (strncmp("was kicked from",message,15)==0) /* 00:00 -!- Nick was kicked from #channel by Nick [Reason] */
@@ -493,9 +616,11 @@ int main(int argc,char *argv[])
           message=&line[i+1];
         }
         else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
+                               /* 00:00 <>>?Nick<<> the personal message */
         {
-          for (i=11;line[i]!='<';i++);
-          nick=&line[11];
+          for (i=10;line[i]!='<';i++);
+          nick=&line[10];
+          if (line[9]=='>') nick++;
           message=&line[i+5];
         }
         else /* 00:00 <?Nick> the message */
@@ -539,17 +664,12 @@ int main(int argc,char *argv[])
           for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
           message[i]='\0';
           nburls++;
-          if ((nburls<=5) || (rand()%nburls==0))
+          if ((nburls<=NBURLS) || (rand()%(nburls/NBURLS)==0))
           {
-            for (i=4;i>0;i--)
-            {
-              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);
+            temp=nburls<=NBURLS?nburls-1:rand()%NBURLS;
+            strcpy(urls[temp].nick,nick);
+            strcpy(urls[temp].url,message);
+            strncpy(urls[temp].shorturl,message,MAXQUOTELENGTH);
           }
         }
         findwords(message);
@@ -561,6 +681,45 @@ int main(int argc,char *argv[])
 
   bestwords(words,0);
 
+  /*** ALIAS ***/
+  
+  if (argc==6)
+  {
+    if ((fic=fopen(argv[5],"rt"))==NULL) { fprintf(stderr,"can't open nick file\n"); exit(1); }
+    while (fscanf(fic,"%s",line)==1)
+    {
+      user=dichotomic(line);
+      fscanf(fic,"%s",line);
+      if (regcomp(&preg,line,0)!=0) { fprintf(stderr,"error in nick file"); exit(1); }
+      temp=users[user].lines;
+      for (i=0;i<nbusers;i++) if ((i!=user) && (regexec(&preg,users[i].nick,0,0,0)==0) && (users[i].lines>=0))
+      {
+        if (users[i].lines>temp) /* for nick alias, keep the random quote of the most used nick */
+        {
+          strcpy(users[user].quote,users[i].quote);
+          temp=users[i].lines;
+        }
+        users[user].lines+=users[i].lines;
+        users[user].letters+=users[i].letters;
+        for (j=0;j<4;j++) users[user].hours[j]+=users[i].hours[j];
+        for (j=0;j<NBCOUNTERS;j++) users[user].counters[j]+=users[i].counters[j];
+        /* "remove" old user */
+        users[i].lines=-1;
+        users[i].letters=-1;
+        for (j=0;j<4;j++) users[i].hours[j]=-1;
+        for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
+      }
+      regfree(&preg);
+    }
+    fclose(fic);
+    /* "remove" the ignored nicks */
+    i=dichotomic("<NULL>");
+    users[i].lines=-1;
+    users[i].letters=-1;
+    for (j=0;j<4;j++) users[i].hours[j]=-1;
+    for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
+  }
+  
   /*** HTML ***/
 
   /* header */
@@ -613,23 +772,25 @@ int main(int argc,char *argv[])
   for (i=1;i<=NBUSERS;i++)
   {
     user=-1;
-    max=-1;
+    max=0;
     for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
     if (user!=-1)
     {
       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\">\"",T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"),users[user].letters/users[user].lines,T("BGTABLE"));
+      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].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"),users[user].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"));
       printhtml(users[user].quote);
       printf("\"</td></tr>\n");
       users[user].lines=-1;
     }    
   }
   printf("</table>\n");
-  if (nbusers>NBUSERS)
+  temp=0;
+  for (i=0;i<=nbusers;i++) if (users[i].lines>=0) temp++;
+  if (temp>0)
   {
     printf("<br>");
-    printf(L("OTHERS"),nbusers-50);
+    printf(L("OTHERS"),temp);
     printf("<br>\n");
   }
   printf("<br><br>\n\n");
@@ -645,7 +806,7 @@ int main(int argc,char *argv[])
     for (j=0;j<4;j++)
     {
       user=-1;
-      max=-1;
+      max=0;
       for (k=0;k<nbusers;k++) if (users[k].hours[j]>max) max=users[user=k].hours[j];
       if (user!=-1)
       {
@@ -700,7 +861,7 @@ int main(int argc,char *argv[])
   printf("</table>\n<br><br>\n\n");
   
   /* footer */
-  printf(L("TIME"),totallines,(int)(time(NULL)-debut));
+  printf(L("TIME"),totallines,days,(int)(time(NULL)-debut));
   printf("<br>\n%s <a href=\"%s\">irssistats %s</a>",L("FOOTER"),URL,VERSION);
   printf("\n\n</center>\n\n</body>\n\n</html>\n");