-/* Usage: irssistats [/path/to/file.conf] */
+/*
+ * irssistats version 0.73
+ *
+ * This tool generates IRC stats based on irssi logs.
+ * Usage: irssistats [/path/to/file.conf]
+ *
+ * Copyright (C) 2002-2004 Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/irssistats/
+ *
+ * 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 <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
+#include <locale.h>
+#ifdef __WIN32__
+#define GLOBALCONF "irssistats.conf"
+#else
+#define GLOBALCONF "/etc/irssistats.conf"
#include <regex.h>
+#endif
/* Config */
-#define MAXUSERS 10000
+#define BASEUSERS 1000
#define MAXNICKLENGTH 50
#define MAXLINELENGTH 2000
#define MAXQUOTELENGTH 100
#define MINWORDLENGTH 5
/* irssistats */
-#define VERSION "0.5"
+#define VERSION "0.73"
#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 8
-#define NBKEYS 38
+#define NBLANGUAGES 11
+#define NBKEYS 41
char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
{
{ /* English language */
{ "English", "en" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statistics for %s by %s" },
{ "LEGEND", "Legend" },
- { "LASTDAYS", "Lastdays statistics" },
+ { "LASTDAYS", "Last days statistics" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Hourly statistics" },
{ "TOPUSERS", "Most active people" },
{ "OTHERS", "There are %d left not ranked..." },
},
{ /* French language */
{ "French", "fr" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statistiques de %s par %s" },
{ "LEGEND", "Légende" },
{ "LASTDAYS", "Statistiques des derniers jours" },
+ { "LASTWEEKS", "Statistiques des dernières semaines" },
+ { "LASTMONTHS", "Statistiques des derniers mois" },
{ "TOPHOURS", "Statistiques horaires" },
{ "TOPUSERS", "Personnes les plus actives" },
{ "OTHERS", "Il reste %d personnes non classées..." },
{ /* German language */
/* contributed by Valentin Gelhorn <valentin.gelhorn@web.de> */
{ "German", "de" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statistiken für %s von %s" },
{ "LEGEND", "Legende" },
{ "LASTDAYS", "Statistik der letzten Tage" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Stündliche Statistik" },
{ "TOPUSERS", "Die aktivsten Personen" },
{ "OTHERS", "Es bleiben noch %d uneingetragene" },
{ "C_EXCLAM", "schreit oft !" },
{ "C_QUESTION", "stellt viele Fragen ?" },
{ "C_ME", "mag /me'en" },
- { "C_TOPIC", "aendert oft das Topico" },
+ { "C_TOPIC", "aendert oft das Topic" },
{ "C_MODE", "aendert oft die Modes" },
{ "C_KICK", "mag /kick'en" },
{ "C_KICKED", "wird oft gekickt"},
{ /* Spanish language */
/* contributed by Alex <ainaker@gmx.net> */
{ "Spanish", "es" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Estadísticas de %s por %s" },
{ "LEGEND", "Leyenda" },
{ "LASTDAYS", "Estadísticas de los últimos días" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Estadísticas por horas" },
{ "TOPUSERS", "Los que más escriben" },
{ "OTHERS", "Hay %d más que no llegaron..." },
{ "C_MONOLOGUE", "Habla solo" }
},
{ /* Polish language */
- /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
+ /* contributed by Jakub Jankowski <shasta@atn.pl> */
{ "Polish", "pl" },
+ { "CHARSET", "ISO-8859-2" },
+ { "HEADER", "Statystyki dla %s zebrane przez %s" },
+ { "LEGEND", "Legenda" },
+ { "LASTDAYS", "Statystyki z ostatnich dni" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
+ { "TOPHOURS", "Statystyki godzinowe" },
+ { "TOPUSERS", "Najaktywniejsi" },
+ { "OTHERS", "Jest jeszcze %d nie sklasyfikowanych..." },
+ { "NBLINES", "linii" },
+ { "NICK", "nick" },
+ { "AVGLETTERS", "liter/liniê" },
+ { "HOURS", "godziny" },
+ { "QUOTE", "losowa wypowied¼" },
+ { "TOPUSERSTIME", "Najaktywniejsi wed³ug pory dnia" },
+ { "RANDTOPICS", "Kilka topików" },
+ { "CHANGEDBY", "ustawiony przez" },
+ { "NEWTOPIC", "topik" },
+ { "RANDURLS", "Kilka URL-i" },
+ { "POSTEDBY", "poda³(a)" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "Najczê¶ciej wystêpuj±ce s³owa" },
+ { "WORD", "s³owo" },
+ { "OCCURRENCES", "wyst±pieñ" },
+ { "BIGNUMBERS", "Kilka wielkopomnych liczb..." },
+ { "NUMBERS", "kategorie" },
+ { "TIME", "Dokonano analizy %d linii (obejmuj±cych %d dni) w czasie %d sekund" },
+ { "FOOTER", "Statystyki wygenerowane przez" },
+ { "C_SMILE", "jest czêsto szczesliwy(a) :)" },
+ { "C_FROWN", "jest czêsto smutny(a) :(" },
+ { "C_EXCLAM", "czêsto KRZYCZY!" },
+ { "C_QUESTION", "zadaje du¿o pytañ?" },
+ { "C_ME", "lubi u¿ywaæ /me" },
+ { "C_TOPIC", "czêsto zmienia topik" },
+ { "C_MODE", "czêsto zmienia tryby kana³u" },
+ { "C_KICK", "lubi kopaæ" },
+ { "C_KICKED", "czêsto wykopywany(a)" },
+ { "C_URL", "podaje du¿o URL-i" },
+ { "C_JOIN", "nie wie czy zostaæ, czy wyj¶æ" },
+ { "C_NICK", "czêsto zmienia nick" },
+ { "C_MONOLOGUE", "uwielbia monologi" }
+ },
+ { /* Polish language */
+ /* contributed by Piotr Jarmuz <coreupper@yahoo.com> */
+ { "Polish", "pl-old" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statystyki dla %s przez %s" },
{ "LEGEND", "Legenda" },
{ "LASTDAYS", "Statystyki z ostatnich dni" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Statystyki godzinne" },
{ "TOPUSERS", "Najaktywniejsi ludzie" },
{ "OTHERS", "Zostalo jeszcze %d nie sklasyfikowanych..." },
{ /* Finnish language */
/* contributed by Antti Huopana <ahuopana@ratol.fi> */
{ "Finnish", "fi" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Kanavan %s tilastot - %s" },
{ "LEGEND", "Merkkien selitykset" },
{ "LASTDAYS", "Viime päivien tilastot" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Tilastot tunneittain" },
{ "TOPUSERS", "Aktiivisimmat ihmiset" },
{ "OTHERS", "Jäljelle jäi %d joita ei listattu..." },
{ /* Italian language */
/* contributed by Coviello Giuseppe <giuseppecoviello@tin.it> <http://coviello.altervista.org> */
{ "Italian", "it" },
+ { "CHARSET", "ISO-8859-1" },
{ "HEADER", "Statistiche per il canale %s di %s" },
{ "LEGEND", "Legenda" },
{ "LASTDAYS", "Statistiche degli ultimi giorni" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "TOPHOURS", "Statistiche in ore" },
{ "TOPUSERS", "Utenti più attivi" },
{ "OTHERS", "Ci sono %d utenti non classificati..." },
},
{ /* 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" },
{ "LEGEND", "Legenda" },
{ "LASTDAYS", "Statistieken van de laatste dagen" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
{ "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" },
+ { "LEGEND", "ïÂÏÚÎÁÞÅÎÉÑ" },
+ { "LASTDAYS", "óÔÁÔÉÓÔÉËÁ ÐÏÓÌÅÄÎÉÈ ÄÎÅÊ" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
+ { "TOPHOURS", "ðÏÞÁÓÏ×ÁÑ ÓÔÁÔÉÓÔÉËÁ" },
+ { "TOPUSERS", "áËÔÉ×ÎÅÊÛÉÅ ÌÀÄÉ" },
+ { "OTHERS", "ïÓÔÁÌÏÓØ %d ÎÅÐÏÄÓÞÉÔÁÎÙÈ..." },
+ { "NBLINES", "ÓÔÒÏËÉ" },
+ { "NICK", "ÎÉË" },
+ { "AVGLETTERS", "ÂÕË×Ù/ÓÔÒÏËÉ" },
+ { "HOURS", "ÞÁÓÙ" },
+ { "QUOTE", "ÓÌÕÞÁÊÎÏÅ ÓÏÏÂÝÅÎÉÅ" },
+ { "TOPUSERSTIME", "áËÔÉ×ÎÅÊÛÉÅ ÌÀÄÉ ÐÏ ×ÒÅÍÅÎÉ ÄÎÑ" },
+ { "RANDTOPICS", "îÅÓËÏÌØËÏ ÔÏÐÉËÏ×" },
+ { "CHANGEDBY", "ÉÚÍÅΣÎ" },
+ { "NEWTOPIC", "ÎÏ×ÙÊ ÔÏÐÉË" },
+ { "RANDURLS", "îÅÓËÏÌØËÏ URLÏ×" },
+ { "POSTEDBY", "ÏÐÕÂÌÉËÏ×ÁÌ" },
+ { "POSTEDURL", "URL" },
+ { "TOPWORDS", "þÁÓÔÏ ÉÓÐÏÌØÚÕÅÍÙÅ ÓÌÏ×Á" },
+ { "WORD", "ÓÌÏ×Ï" },
+ { "OCCURRENCES", "ÐÒÏÉÛÅÓÔ×ÉÑ" },
+ { "BIGNUMBERS", "îÅÓËÏÌØËÏ ÂÏÌØÛÉÈ ÞÉÓÅÌ..." },
+ { "NUMBERS", "ÞÉÓÌÁ" },
+ { "TIME", "%d ÓÔÒÏË (%d ÄÎÅÊ) ÏÂÒÁÂÏÔÁÎÏ ÚÁ %d ÓÅËÕÎÄ" },
+ { "FOOTER", "óÔÁÔÉÓÔÉËÁ ÓÇÅÎÅÒÉÒÏ×ÁÎÁ" },
+ { "C_SMILE", "ÞÁÓÔÏ ÓÞÁÓÌÉ× :)" },
+ { "C_FROWN", "ÞÁÓÔÏ ÎÅÓÞÁÓÔÅÎ :(" },
+ { "C_EXCLAM", "ÍÎÏÇÏ ×ÏÓËÌÉÃÁÅÔ !" },
+ { "C_QUESTION", "ÚÁÄÁ£Ô ÍÎÏÇÏ ×ÏÐÒÏÓÏ× ?" },
+ { "C_ME", "ÌÀÂÉÔ /me command" },
+ { "C_TOPIC", "ÞÁÓÔÏ ÍÅÎÑÅÔ ÔÏÐÉË" },
+ { "C_MODE", "ÞÁÓÔÏ ÍÅÎÑÅÔ ÒÅÖÉÍÙ" },
+ { "C_KICK", "ÌÀÂÉÔ /kick" },
+ { "C_KICKED", "ÞÁÓÔÏ ×ÙËÉÄÙ×ÁÀÔ" },
+ { "C_URL", "ÐÕÂÌÉËÕÅÔ ÍÎÏÇÏ URLÏ×" },
+ { "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" },
+ { "LASTWEEKS", "Last weeks statistics" },
+ { "LASTMONTHS", "Last months statistics" },
+ { "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 language=0; /* default to english */
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";
+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;
time_t debut;
+int top_words=1; /* 0 = disabled */
+int ranking=0; /* 0 = lines ; 1 = words ; 2 = letters */
+int quarter=0; /* 1 = enabled */
+int months=0; /* 1 = enabled */
+int weeks=0; /* 1 = enabled */
+int photo_size=60;
-struct
+struct user
{
char nick[MAXNICKLENGTH];
int lines;
+ int words;
int letters;
int hours[4];
char quote[MAXQUOTELENGTH+1];
int counters[NBCOUNTERS];
+ char *photo;
int temp;
-} users[MAXUSERS];
+} *users;
int nbusers=0;
+int maxusers=BASEUSERS;
struct
{
char nick[MAXNICKLENGTH];
char url[MAXLINELENGTH];
char shorturl[MAXQUOTELENGTH+1];
-} urls[5];
+} urls[NBURLS];
int nburls=0;
struct
{
char nick[MAXNICKLENGTH];
char topic[MAXQUOTELENGTH+1];
-} topics[5];
+} topics[NBTOPICS];
int nbtopics=0;
struct
{
int lines;
int hours[4];
-} lastdays[31];
+} lastdays[31], lastweeks[31], lastmonths[31];
int days=0;
+char currday[16];
+int currwday=-1, currmon=-1;
-int hours[24];
+int hours[24*4];
int lines=0;
struct letter
char word[MAXLINELENGTH];
} topwords[NBWORDS];
+struct rusletter
+{
+ int nb;
+ struct rusletter *next[33];
+} ruswords;
+
#define isletter(c) (((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))
#define lowercase(c) (((c>='A')&&(c<='Z'))?c-'A'+'a':c)
-void findwords(char *message)
+//#define lowercase(c) (c | 0x20)
+#define isrusletter(c) (memchr(koi,c,66)==NULL?0:1)
+
+const char koi[] = {
+193,194,215,199,196,197,163,214,218,201,202,203,204,205,206,207,208,210,
+211,212,213,198,200,195,222,219,221,216,223,217,220,192,209,
+225,226,247,231,228,229,179,246,250,233,234,235,236,237,238,239,240,242,
+243,244,245,230,232,227,254,251,253,248,255,249,252,224,241
+};
+int lowruscase(char c)
+{
+ char *ctmp_p;
+ int ch=0;
+ if (memchr(koi,c,66)==NULL) return koi[0];
+ ch=strlen(koi)-strlen(memchr(koi,c,66));
+ if (ch>33) return ch-33; else return ch;
+}
+/* cp1251 for encoding into koi8-r
+const char win[] = {
+224,225,226,227,228,229,184,230,231,232,233,234,235,236,237,238,239,240,
+241,242,243,244,245,246,247,248,249,252,250,251,253,254,255,
+192,193,194,195,196,197,168,198,199,200,201,202,203,204,205,206,207,208,
+209,210,211,212,213,214,215,216,217,220,218,219,221,222,223
+};*/
+
+
+
+int findruswords(char *message)
+{
+ int i,c,n=0;
+ //char *tmp_p;
+ struct rusletter *pos,*tmp;
+ for (;;)
+ {
+ while (!isrusletter(*message)) if (*message=='\0') return n; else message++;
+ pos=&ruswords;
+ while (isrusletter(*message))
+ {
+ c=lowruscase(*message);
+ /*tmp_p=memchr(koi,message[0],33);
+ if (tmp_p==NULL) return n;
+ c=strlen(koi)-strlen(tmp_p);*/
+ if (pos->next[(int)c]==NULL)
+ {
+ tmp=malloc(sizeof(struct rusletter));
+ if (tmp==NULL)
+ {
+ fprintf(stderr, "findruswords(): malloc failure\n");
+ exit(1);
+ }
+ tmp->nb=0;
+ for (i=0;i<33;i++) tmp->next[i]=NULL;
+ pos->next[(int)c]=tmp;
+ }
+ pos=pos->next[(int)c];
+ message++;
+ }
+ pos->nb++;
+ n++;
+ }
+ return n;
+}
+
+
+void freeruswords(struct rusletter *pos)
{
- int i,c;
+ int i;
+ for (i=0;i<33;i++) if (pos->next[i]!=NULL)
+ {
+ freeruswords(pos->next[i]);
+ free(pos->next[i]);
+ (*pos).next[i]=NULL;
+ }
+}
+
+int findwords(char *message)
+{
+ int i,c,n=0;
struct letter *pos,*tmp;
for (;;)
{
- while (!isletter(*message)) if (*message=='\0') return; else message++;
+ while (!isletter(*message)) if (*message=='\0') return n; else message++;
pos=&words;
while (isletter(*message))
{
if (pos->next[(int)c]==NULL)
{
tmp=malloc(sizeof(struct letter));
+ if (tmp==NULL)
+ {
+ fprintf(stderr, "findwords(): malloc failure\n");
+ exit(1);
+ }
tmp->nb=0;
for (i=0;i<26;i++) tmp->next[i]=NULL;
pos->next[(int)c]=tmp;
message++;
}
pos->nb++;
+ n++;
}
- return;
+ return n;
}
char tempword[MAXLINELENGTH];
tempword[cur]='\0';
}
+void bestruswords(struct rusletter pos,int cur)
+{
+ int i,j;
+ if ((cur>=MINWORDLENGTH)&&(pos.nb>topwords[NBWORDS-1].nb))
+ {
+ for (i=0;pos.nb<topwords[i].nb;i++);
+ for (j=NBWORDS-1;j>i;j--)
+ {
+ topwords[j].nb=topwords[j-1].nb;
+ strcpy(topwords[j].word,topwords[j-1].word);
+ }
+ topwords[i].nb=pos.nb;
+ strcpy(topwords[i].word,tempword);
+ }
+ for (i=0;i<33;i++) if (pos.next[i]!=NULL)
+ {
+ tempword[cur]=koi[i];
+ bestruswords(*(pos.next[i]),cur+1);
+ }
+ tempword[cur]='\0';
+}
+
void freewords(struct letter *pos)
{
int i;
if (strcmp(nick,users[start].nick)!=0)
{
nbusers++;
- if (nbusers>=MAXUSERS) { fprintf(stderr,"too many users\n"); exit(1); }
+ if (nbusers>=maxusers)
+ {
+ maxusers+=BASEUSERS;
+ if (debug==2) fprintf(stderr,"allocating more users : %d\n",maxusers);
+ if ((users=realloc(users,maxusers*sizeof(struct user)))==NULL) { fprintf(stderr,"too many users : unable to realloc memory\n"); exit(1); }
+ }
for (i=nbusers-1;i>start;i--)
{
strcpy(users[i].nick,users[i-1].nick);
users[i].lines=users[i-1].lines;
+ users[i].words=users[i-1].words;
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];
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].words=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;
users[start].temp=0;
+ users[start].photo=NULL;
}
return(start);
}
+void day_changed(char* date)
+{
+ int i,j;
+ char newday[16];
+ struct tm currdate;
+
+ memcpy(newday, date, 11);
+ if (date[13]==':')
+ memcpy(newday+11, date+20, 4);
+ else
+ memcpy(newday+11, date+11, 4);
+ newday[15]=0;
+ if (memcmp(currday, newday, 15)!=0)
+ {
+ /* we do not have a "current" day yet? */
+ if (currday[0]!=0)
+ {
+ for (i=30;i>0;i--)
+ {
+ lastdays[i].lines=lastdays[i-1].lines;
+ for (j=0;j<4;j++) lastdays[i].hours[j]=lastdays[i-1].hours[j];
+ }
+ lastdays[0].lines=0;
+ for (j=0;j<4;j++) lastdays[0].hours[j]=0;
+ days++;
+ }
+ memcpy(currday, newday, 15);
+ if (debug==2)
+ fprintf(stderr, "day %d changed to: %s\n", days, currday);
+
+ /* try to parse the date for weeks/months stats */
+ if (strptime(currday, "%a %b %d %Y", &currdate))
+ {
+ /* each monday we change the week number */
+ if (currdate.tm_wday == 1)
+ {
+ for (i=30;i>0;i--)
+ {
+ lastweeks[i].lines=lastweeks[i-1].lines;
+ for (j=0;j<4;j++) lastweeks[i].hours[j]=lastweeks[i-1].hours[j];
+ }
+ lastweeks[0].lines=0;
+ for (j=0;j<4;j++) lastweeks[0].hours[j]=0;
+ }
+ /* if the month has changed */
+ if (currdate.tm_mon != currmon && currmon > 0)
+ {
+ for (i=30;i>0;i--)
+ {
+ lastmonths[i].lines=lastmonths[i-1].lines;
+ for (j=0;j<4;j++) lastmonths[i].hours[j]=lastmonths[i-1].hours[j];
+ }
+ lastmonths[0].lines=0;
+ for (j=0;j<4;j++) lastmonths[0].hours[j]=0;
+ }
+ currwday = currdate.tm_wday;
+ currmon = currdate.tm_mon;
+
+ }
+ } else {
+ if (debug==2)
+ fprintf(stderr, "but day did not change\n");
+ }
+}
+
void parse_log(char *logfile)
{
FILE *fic;
int i,j;
char *nick,*message;
int nickstart;
- int mononick,monolines;
+ int mononick=-1,monolines=0;
int temp,hour;
+ int timelen;
if ((fic=fopen(logfile,"rt"))==NULL) { fprintf(stderr,"can't open log file \"%s\"\n",logfile); exit(1); }
if (debug) printf("working on %s : ",channel);
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++;
if (totallines%10000==0 && debug) { printf("."); fflush(stdout); }
- if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
+ if (strncmp("--- Log opened",line,14)==0) /* --- Log opened Wed May 01 00:00 2002 */
{
- for (i=30;i>0;i--)
- {
- lastdays[i].lines=lastdays[i-1].lines;
- for (j=0;j<4;j++) lastdays[i].hours[j]=lastdays[i-1].hours[j];
- }
- lastdays[0].lines=0;
- for (j=0;j<4;j++) lastdays[0].hours[j]=0;
- days++;
+ if (debug==2)
+ fprintf(stderr, "log %s opened, ", logfile);
+ day_changed(line+15);
}
- else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by (Nick, Nick2, )Nick3 */
+ if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
{
- for (i=strlen(line);line[i]!=' ';i--);
- nick=&line[i+1];
- users[dichotomic(nick)].counters[D_MODE]++;
+ if (debug==2)
+ fprintf(stderr, "within log file, ");
+ day_changed(line+16);
}
- else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
+ else
{
- for (i=10;line[i]!=' ';i++);
- line[i]='\0';
- nick=&line[10];
- message=&line[i+1];
- if (strncmp("changed the topic of",message,20)==0) /* 00:00 -!- Nick changed the topic of #channel to: new topic */
+ /* timelen is number of characters occupied by time 00:00.. plus any space */
+ timelen = 5;
+ if (line[timelen] == ':' && isdigit(line[timelen+1]) && isdigit(line[timelen+2]))
+ timelen += 3;
+ if (line[timelen] == ' ')
+ timelen++;
+ if (strncmp("-!- mode/",&line[timelen],9)==0) /* 00:00 -!- mode/#channel [...] by (Nick, Nick2, )Nick3 */
{
- users[dichotomic(nick)].counters[D_TOPIC]++;
- for (i=21;message[i]!=':';i++);
- message=&message[i+2];
- nbtopics++;
- if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
- {
- 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] */
- {
- 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]++;
+ for (i=strlen(line);line[i]!=' ';i--);
+ nick=&line[i+1];
+ users[dichotomic(nick)].counters[D_MODE]++;
}
- 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]=='*'))
- {
- line[2]='\0';
- hour=atoi(line);
- if (line[7]=='*') /* 00:00 * Nick the message */
+ else if (strncmp("-!-",&line[timelen],3)==0) /* 00:00 -!- Nick something... */
{
- for (i=9;line[i]!=' ';i++);
- nick=&line[9];
+ 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[timelen+4];
message=&line[i+1];
+ 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];
+ nbtopics++;
+ if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
+ {
+ 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] */
+ {
+ 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[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
- /* 00:00 <>>?Nick<<> the personal message */
- {
- for (i=10;line[i]!='<';i++);
- nick=&line[10];
- if (line[9]=='>') nick++;
- message=&line[i+5];
- }
- else /* 00:00 <?Nick> the message */
+ else if ((line[timelen]=='<') || (line[timelen+1]=='*'))
{
+ line[2]='\0';
+ hour=atoi(line);
+ if (line[timelen+1]=='*') /* 00:00 * Nick the message */
+ {
+ for (i=timelen+3;line[i]!=' ' && i <= timelen+3+MAXNICKLENGTH;i++);
+ if(i > timelen+3+MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
+ nick=&line[timelen+3];
+ message=&line[i+1];
+ }
+ else if (line[timelen+1]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
+ /* 00:00 <>>?Nick<<> the personal message */
+ {
+ for (i=timelen+4;line[i]!='<' && i <= timelen+4+MAXNICKLENGTH;i++);
+ if(i > timelen+4+MAXNICKLENGTH) {
+ if(debug) {
+ fprintf(stderr,"nick on line %d is too long, skipping line\n",totallines);
+ }
+ continue;
+ }
+ nick=&line[timelen+4];
+ if (line[timelen+3]=='>') nick++;
+ message=&line[i+5];
+ }
+ else /* 00:00 <?Nick> the message */
+ {
- /*
- * Irssi doesn't log channel mode with show_nickmode = OFF
- * the following covers op, half-op, voice and show_nickmode_empty
- */
- if (line[7]=='@' || line[7]=='%' || line[7]=='+' || line[7]==' ') {
- nickstart = 8;
- } else {
- nickstart = 7;
+ /*
+ * Irssi doesn't log channel mode with show_nickmode = OFF
+ * the following covers op, half-op, voice and show_nickmode_empty
+ */
+ switch (line[timelen+1])
+ {
+ case '@':
+ case '%':
+ case '+':
+ case ' ':
+ nickstart = timelen+2;
+ break;
+ default:
+ nickstart = timelen+1;
+ break;
+ }
+
+ 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];
}
-
- for (i=nickstart;line[i]!='>';i++);
- nick=&line[nickstart];
- message=&line[i+2];
- }
- line[i]='\0';
- 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+=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++;
- if ((nburls<=NBURLS) || (rand()%(nburls/NBURLS)==0))
+ /* remove identified character from nick (invalid nick character anyway) */
+ if (nick[0] == '+')
+ fprintf(stderr, "nick starts with +! %s\n", nick);
+ if (line[i-1] == '+' || line[i-1] == '*')
+ i--;
+ line[i]='\0';
+ i=dichotomic(nick);
+ if (line[timelen+1]=='*') 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++;
+ if (top_words || ranking==1)
+ {
+ if (L("CHARSET")=="KOI8-R") users[i].words+=findwords(message)+findruswords(message);
+ else users[i].words+=findwords(message);
+ }
+ users[i].letters+=j;
+ users[i].hours[hour/6]++;
+ lastdays[0].lines++;
+ lastdays[0].hours[hour/6]++;
+ lastweeks[0].lines++;
+ lastweeks[0].hours[hour/6]++;
+ lastmonths[0].lines++;
+ lastmonths[0].hours[hour/6]++;
+ lines++;
+ if (quarter)
+ {
+ line[5]='\0';
+ hour=hour*4+atoi(&line[3])/15;
+ }
+ 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)
{
- temp=nburls<=NBURLS?nburls-1:rand()%NBURLS;
- strcpy(urls[temp].nick,nick);
- strcpy(urls[temp].url,message);
- strncpy(urls[temp].shorturl,message,MAXQUOTELENGTH);
+ users[i].counters[D_URL]++;
+ for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
+ message[i]='\0';
+ nburls++;
+ if ((nburls<=NBURLS) || (rand()%(nburls/NBURLS)==0))
+ {
+ 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);
}
pos=0;
}
if (debug) printf(" done\n");
}
+#ifndef __WIN32__
void parse_nick(char *nickfile)
{
FILE *fic;
users[user].temp=users[i].temp;
}
users[user].lines+=users[i].lines;
+ users[user].words+=users[i].words;
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].words=-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;
/* "remove" the ignored nicks */
i=dichotomic("<NULL>");
users[i].lines=-1;
+ users[i].words=-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;
}
+#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 i,j,k;
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); }
fprintf(fic,"<!-- Generated by irssistats %s : %s -->\n\n",VERSION,URL);
fprintf(fic,"<html>\n\n<head>\n<title>");
fprintf(fic,L("HEADER"),channel,maintainer);
- fprintf(fic,"</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n");
+ fprintf(fic,"</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\" />\n",L("CHARSET"));
if (refresh_time)
fprintf(fic,"<meta http-equiv=\"Refresh\" content=\"%d\" />\n",refresh_time);
- fprintf(fic,"<link rel=\"stylesheet\" type=\"text/css\" href=\"%s.css\" />\n",theme);
+ strcpy(line, theme);
+ subtheme=strtok(line,",");
+ fprintf(fic,"<link rel=\"stylesheet\" type=\"text/css\" href=\"%s.css\" title=\"%s\" />\n",subtheme,subtheme);
+ while ((subtheme=strtok(NULL,","))!=NULL)
+ fprintf(fic,"<link rel=\"alternate stylesheet\" type=\"text/css\" href=\"%s.css\" title=\"%s\" />\n",subtheme,subtheme);
fprintf(fic,"</head>\n\n");
fprintf(fic,"<body>\n\n");
}
for (i=0;i<4;i++) fprintf(fic,"<td><div class=\"h%d\" style=\"width: 40px\"></div></td><td>%s %d-%d</td>\n",i+1,L("HOURS"),i*6,i*6+5);
fprintf(fic,"</tr>\n</table>\n</div>\n\n");
+ if (months)
+ {
+ /* last months */
+ fprintf(fic,"<div id=\"irssistats_lastmonths\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("LASTMONTHS"));
+ max=-1;
+ for (i=30;i>=0;i--) if (lastmonths[i].lines>max) max=lastmonths[i].lines;
+ for (i=30;i>=0;i--)
+ {
+ fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%d</small>",lastmonths[i].lines);
+ for (j=0;j<4;j++) if (lastmonths[i].hours[j]!=0) fprintf(fic,"<div class=\"v%d\" style=\"height:%dpx\"></div>",j+1,150*lastmonths[i].hours[j]/max);
+ fprintf(fic,"</td>\n");
+ }
+ fprintf(fic,"</tr>\n<tr>\n");
+ for (i=30;i>=0;i--)
+ fprintf(fic,"<th>%d</th>\n",i);
+ fprintf(fic,"</tr>\n</table>\n</div>\n\n");
+ }
+
+ if (weeks)
+ {
+ /* last weeks */
+ fprintf(fic,"<div id=\"irssistats_lastweeks\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("LASTWEEKS"));
+ max=-1;
+ for (i=30;i>=0;i--) if (lastweeks[i].lines>max) max=lastweeks[i].lines;
+ for (i=30;i>=0;i--)
+ {
+ fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%d</small>",lastweeks[i].lines);
+ for (j=0;j<4;j++) if (lastweeks[i].hours[j]!=0) fprintf(fic,"<div class=\"v%d\" style=\"height:%dpx\"></div>",j+1,150*lastweeks[i].hours[j]/max);
+ fprintf(fic,"</td>\n");
+ }
+ fprintf(fic,"</tr>\n<tr>\n");
+ for (i=30;i>=0;i--)
+ fprintf(fic,"<th>%d</th>\n",i);
+ fprintf(fic,"</tr>\n</table>\n</div>\n\n");
+ }
+
/* last days */
fprintf(fic,"<div id=\"irssistats_lastdays\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("LASTDAYS"));
max=-1;
for (i=30;i>=0;i--) if (lastdays[i].lines>max) max=lastdays[i].lines;
for (i=30;i>=0;i--)
{
- fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%d</small>",lastdays[i].lines); /* width=\"15\" */
+ fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%d</small>",lastdays[i].lines);
for (j=0;j<4;j++) if (lastdays[i].hours[j]!=0) fprintf(fic,"<div class=\"v%d\" style=\"height:%dpx\"></div>",j+1,150*lastdays[i].hours[j]/max);
fprintf(fic,"</td>\n");
}
/* top hours */
fprintf(fic,"<div id=\"irssistats_tophours\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("TOPHOURS"));
max=-1;
- for (i=0;i<24;i++) if (hours[i]>max) max=hours[i];
- for (i=0;i<24;i++)
+ for (i=0;i<24*4;i++) if (hours[i]>max) max=hours[i];
+ if (quarter) for (i=0;i<24*4;i++)
+ {
+ fprintf(fic,"<td align=\"center\" valign=\"bottom\">");
+ if (hours[i]!=0) fprintf(fic,"<div class=\"v%d\" style=\"width:4px;height:%dpx\"></div>",i/4/6+1,150*hours[i]/max);
+ fprintf(fic,"</td>\n");
+ }
+ else for (i=0;i<24;i++)
{
- fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%.1f%%</small>",lines!=0?(float)100*hours[i]/lines:0); /* width=\"15\" */
+ fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%.1f%%</small>",lines!=0?(float)100*hours[i]/lines:0);
if (hours[i]!=0) fprintf(fic,"<div class=\"v%d\" style=\"height:%dpx\"></div>",i/6+1,150*hours[i]/max);
fprintf(fic,"</td>\n");
}
fprintf(fic,"</tr>\n<tr>\n");
for (i=0;i<24;i++)
- fprintf(fic,"<th>%d</th>\n",i);
+ if (quarter) fprintf(fic,"<th colspan=\"4\">%d</th>\n",i);
+ else fprintf(fic,"<th>%d</th>\n",i);
fprintf(fic,"</tr>\n</table>\n</div>\n\n");
/* top users */
fprintf(fic,"<div id=\"irssistats_topusers\">\n<h2>%s</h2>\n",L("TOPUSERS"));
- 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"));
+ 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>\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>\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;
max=0;
- for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
+ switch (ranking)
+ {
+ case 0:
+ for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
+ break;
+ case 1:
+ for (j=0;j<nbusers;j++) if (users[j].words>max) max=users[user=j].words;
+ break;
+ case 2:
+ for (j=0;j<nbusers;j++) if (users[j].letters>max) max=users[user=j].letters;
+ break;
+ }
if (user!=-1)
{
- fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].lines);
+ switch (ranking)
+ {
+ case 0:
+ fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].lines);
+ break;
+ case 1:
+ fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].words);
+ break;
+ case 2:
+ fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].letters);
+ break;
+ }
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);
+ }
+ fprintf(fic,"</tr>\n");
users[user].lines=-1;
+ users[user].words=-1;
+ users[user].letters=-1;
}
}
fprintf(fic,"</table>\n");
fprintf(fic,"</table>\n</div>\n\n");
/* top words */
- fprintf(fic,"<div id=\"irssistats_topwords\">\n<h2>%s</h2>\n",L("TOPWORDS"));
- fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th></tr>\n",L("WORD"),L("OCCURRENCES"));
- for (i=0;i<NBWORDS;i++)
- if (topwords[i].nb!=0) fprintf(fic,"<tr><td>%d</td><td>\"%s\"</td><td>%d</td></tr>\n",i+1,topwords[i].word,topwords[i].nb);
- fprintf(fic,"</table>\n</div>\n\n");
-
+ if (top_words)
+ {
+ fprintf(fic,"<div id=\"irssistats_topwords\">\n<h2>%s</h2>\n",L("TOPWORDS"));
+ fprintf(fic,"<table>\n<tr><th></th><th>%s</th><th>%s</th></tr>\n",L("WORD"),L("OCCURRENCES"));
+ for (i=0;i<NBWORDS;i++)
+ if (topwords[i].nb!=0) fprintf(fic,"<tr><td>%d</td><td>\"%s\"</td><td>%d</td></tr>\n",i+1,topwords[i].word,topwords[i].nb);
+ fprintf(fic,"</table>\n</div>\n\n");
+ }
+
/* big numbers */
fprintf(fic,"<div id=\"irssistats_bignumbers\">\n<h2>%s</h2>\n",L("BIGNUMBERS"));
fprintf(fic,"<table>\n<tr><th>%s</th><th>%s</th><th>%s</th></tr>\n",L("NICK"),L("NUMBERS"),L("NBLINES"));
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 */
+ fprintf(fic,"</div>\n\n");
+ if (strcmp("none",footer)==0)
{
- fprintf(fic,"\n\n</body>\n\n</html>\n");
+ fprintf(fic,"</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];
char value[MAXLINELENGTH];
int configlines=0;
- int i;
+ int i,j;
if (configfile!=NULL)
{
}
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("verbose",value)==0) { debug=2; fprintf(stderr,"switching to verbose output\n"); }
else { fprintf(stderr,"unknown value for \"debug\" option, must be \"normal\", \"verbose\" or \"none\"\n"); exit(1); }
- } else
+ }
+ else
if (strcmp("channel",keyword)==0)
{
}
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);
+ if (L("CHARSET")=="KOI8-R") bestruswords(ruswords,0);
gen_xhtml(value);
/* reset variables */
nburls=0;
nbtopics=0;
days=0;
- for (i=0;i<24;i++) hours[i]=0;
+ currwday=-1;
+ currmon=-1;
+ for (i=0;i<24*4;i++) hours[i]=0;
lines=0;
+ for (i=0;i<31;i++)
+ {
+ lastdays[i].lines=0;
+ lastweeks[i].lines=0;
+ lastmonths[i].lines=0;
+ for (j=0;j<4;j++)
+ {
+ lastdays[i].hours[j]=0;
+ lastweeks[i].hours[j]=0;
+ lastmonths[i].hours[j]=0;
+ }
+ }
freewords(&words);
+ freeruswords(&ruswords);
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
+
+ if (strcmp("top_words",keyword)==0)
+ {
+ if (debug==2) fprintf(stderr,"setting top_words to \"%s\"\n",value);
+ if (strcmp("no",value)==0) top_words=0;
+ else if (strcmp("yes",value)==0) top_words=1;
+ else { fprintf(stderr,"unknown value for \"top_words\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+ }
+ else
+
+ if (strcmp("ranking",keyword)==0)
+ {
+ if (strcmp("lines",value)==0) ranking=0;
+ else
+ if (strcmp("words",value)==0) ranking=1;
+ else
+ if (strcmp("letters",value)==0) ranking=2;
+ else { fprintf(stderr,"unknown value for \"ranking\" option, must be \"lines\", \"words\" or \"letters\"\n"); exit(1); }
+ }
+ else
+
+ if (strcmp("quarter",keyword)==0)
+ {
+ if (debug==2) fprintf(stderr,"setting quarter to \"%s\"\n",value);
+ if (strcmp("no",value)==0) quarter=0;
+ else if (strcmp("yes",value)==0) quarter=1;
+ else { fprintf(stderr,"unknown value for \"quarter\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+ }
+ else
+
+ if (strcmp("months",keyword)==0)
+ {
+ if (debug==2) fprintf(stderr,"setting months to \"%s\"\n",value);
+ if (strcmp("no",value)==0) months=0;
+ else if (strcmp("yes",value)==0) months=1;
+ else { fprintf(stderr,"unknown value for \"months\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+ }
+ else
+
+ if (strcmp("weeks",keyword)==0)
+ {
+ if (debug==2) fprintf(stderr,"setting weeks to \"%s\"\n",value);
+ if (strcmp("no",value)==0) weeks=0;
+ else if (strcmp("yes",value)==0) weeks=1;
+ else { fprintf(stderr,"unknown value for \"weeks\" option, must be \"yes\" or \"no\"\n"); exit(1); }
}
+ else
- else { fprintf(stderr,"error in config file : \"%s\" is an unknown keyword (line %d)\n",keyword,configlines); exit(1); }
+ { fprintf(stderr,"error in config file : \"%s\" is an unknown keyword (line %d)\n",keyword,configlines); exit(1); }
}
}
fclose(fic);
int main(int argc,char *argv[])
{
+ (void) setlocale(LC_ALL, "");
+
+ if ((users=malloc(maxusers*sizeof(struct user)))==NULL) { fprintf(stderr,"unable to malloc memory\n"); exit(1); }
srand(debut=time(NULL));
if (argc==1) parse_config(NULL);
else if (argc==2) parse_config(argv[1]);