/* * irssistats version 0.75 * * This tool generates IRC stats based on irssi logs. * Usage: irssistats [/path/to/file.conf] * * Copyright (C) 2002-2004 Antoine Jacquet * 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 #include #include #include #include #include #ifdef __WIN32__ #define GLOBALCONF "irssistats.conf" #else #define GLOBALCONF "/etc/irssistats.conf" #include #endif /* Config */ #define BASEUSERS 1000 #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.75" #define URL "http://royale.zerezo.com/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 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", "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..." }, { "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 (%d days) 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 */ { "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..." }, { "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 (%d jours) 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" } }, { /* German language */ /* contributed by Valentin Gelhorn */ { "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" }, { "NBLINES", "Zeilen" }, { "NICK", "Nick" }, { "AVGLETTERS", "Buchstaben/Zeile" }, { "HOURS", "Stunden" }, { "QUOTE", "Zufä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äufigsten benutze Wö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ü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 Topic" }, { "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", "ändert oft seinen Nick" }, { "C_MONOLOGUE", "spricht oft Monologe" } }, { /* Spanish language */ /* contributed by Alex */ { "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..." }, { "NBLINES", "líneas" }, { "NICK", "nick" }, { "AVGLETTERS", "letras por línea" }, { "HOURS", "horas" }, { "QUOTE", "Frase aleatoria" }, { "TOPUSERSTIME", "Los que más escriben según la hora" }, { "RANDTOPICS", "Algunos topics" }, { "CHANGEDBY", "Puestos por" }, { "NEWTOPIC", "topic" }, { "RANDURLS", "Algunas URLs" }, { "POSTEDBY", "puestas por" }, { "POSTEDURL", "URL" }, { "TOPWORDS", "Palabras más usadas" }, { "WORD", "Palabra" }, { "OCCURRENCES", "Frecuencia" }, { "BIGNUMBERS", "Algunos datos..." }, { "NUMBERS", "Número de veces" }, { "TIME", "%d lineas (%d días) procesadas en %d segundos" }, { "FOOTER", "Estadísticas generadas por" }, { "C_SMILE", "Suele estar felí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 Jakub Jankowski */ { "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 */ { "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..." }, { "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" } }, { /* Finnish language */ /* contributed by Antti Huopana */ { "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..." }, { "NBLINES", "rivit" }, { "NICK", "nikki" }, { "AVGLETTERS", "kirjainta/rivi" }, { "HOURS", "tunnit" }, { "QUOTE", "satunnainen viesti" }, { "TOPUSERSTIME", "Vuorokauden ajan mukaan aktiivisimmat" }, { "RANDTOPICS", "Joitakin aiheita" }, { "CHANGEDBY", "vaihtaja" }, { "NEWTOPIC", "aihe" }, { "RANDURLS", "Joitakin URLeja" }, { "POSTEDBY", "lähettäjä" }, { "POSTEDURL", "URL" }, { "TOPWORDS", "Eniten käytettyjä sanoja" }, { "WORD", "sana" }, { "OCCURRENCES", "käytetty" }, { "BIGNUMBERS", "Joitakin isoja lukuja..." }, { "NUMBERS", "luvut" }, { "TIME", "%d riviä (%d päivää) parsittu %d sekunnissa" }, { "FOOTER", "Tilastot on generoinut" }, { "C_SMILE", "on usein iloinen :)" }, { "C_FROWN", "on usein surullinen :(" }, { "C_EXCLAM", "möykkää paljon !" }, { "C_QUESTION", "kyselee liikaa ?" }, { "C_ME", "pitää itsestään" }, { "C_TOPIC", "vaihtaa usein aihetta" }, { "C_MODE", "haluaa elää muuttuvassa maailmassa" }, { "C_KICK", "pitää potkimisesta" }, { "C_KICKED", "tykkää tulla potkituksi" }, { "C_URL", "surffailee liikaa" }, { "C_JOIN", "ei tiedä ollakko vai eikö olla" }, { "C_NICK", "kärsii identiteettiongelmista" }, { "C_MONOLOGUE", "höpöttää paljon itsekseen" } }, { /* Italian language */ /* contributed by Coviello Giuseppe */ { "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..." }, { "NBLINES", "righe" }, { "NICK", "nick" }, { "AVGLETTERS", "lettere/righe" }, { "HOURS", "ore" }, { "QUOTE", "messaggio casuale" }, { "TOPUSERSTIME", "Utenti più attivi del giorno (divisi per fasce orarie)" }, { "RANDTOPICS", "Alcuni topic" }, { "CHANGEDBY", "cambiato da" }, { "NEWTOPIC", "nuovo topic" }, { "RANDURLS", "ALcuni URL" }, { "POSTEDBY", "postato da" }, { "POSTEDURL", "URL" }, { "TOPWORDS", "Le parole più usate" }, { "WORD", "parola" }, { "OCCURRENCES", "usata" }, { "BIGNUMBERS", "Alcuni numeri ..." }, { "NUMBERS", "numeri" }, { "TIME", "%d righe (%d giorni) esaminate in %d secondi" }, { "FOOTER", "Statistiche generate da" }, { "C_SMILE", "è spesso felice :)" }, { "C_FROWN", "è spesso triste :(" }, { "C_EXCLAM", "esclama molto !" }, { "C_QUESTION", "fa molte domande ?" }, { "C_ME", "ama il comando /me" }, { "C_TOPIC", "cambia spesso il topic" }, { "C_MODE", "cambia spesso i mode" }, { "C_KICK", "ama /kick(are)" }, { "C_KICKED", "è kickato spesso" }, { "C_URL", "posta molti URL" }, { "C_JOIN", "non sa se è ora di andare o restare" }, { "C_NICK", "cambia spesso il nick" }, { "C_MONOLOGUE", "fa molti monologhi" } }, { /* Dutch language */ /* contributed by Jeroen Ubbink */ /* updated by Wouter Horré */ { "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 mensen die de top niet haalden..." }, { "NBLINES", "regels" }, { "NICK", "nick" }, { "AVGLETTERS", "letters/lijn" }, { "HOURS", "uren" }, { "QUOTE", "Willekeurige regel" }, { "TOPUSERSTIME", "Meest actieve mensen per tijdstip per dag" }, { "RANDTOPICS", "Enkele topics" }, { "CHANGEDBY", "gewijzigd door" }, { "NEWTOPIC", "nieuwe topic" }, { "RANDURLS", "Enkele URLs" }, { "POSTEDBY", "Geplaatst door" }, { "POSTEDURL", "URL" }, { "TOPWORDS", "Meest gebruikte woorden" }, { "WORD", "woord" }, { "OCCURRENCES", "aantal" }, { "BIGNUMBERS", "Enkele grote aantallen..." }, { "NUMBERS", "numbers" }, { "TIME", "%d regels (%d dagen) verwerkt in %d seconden" }, { "FOOTER", "Statistieken gegenereerd door" }, { "C_SMILE", "is vaak vrolijk :)" }, { "C_FROWN", "is vaak droevig :(" }, { "C_EXCLAM", "schreeuwt veel !" }, { "C_QUESTION", "stelt veel vragen ?" }, { "C_ME", "vindt /me een leuk commando" }, { "C_TOPIC", "verandert vaak de topic" }, { "C_MODE", "verandert vaak de modes" }, { "C_KICK", "vindt /kick erg leuk" }, { "C_KICKED", "wordt vaak gekickt" }, { "C_URL", "plaatst veel URLs" }, { "C_JOIN", "twijfelt tussen blijven of gaan" }, { "C_NICK", "verandert vaak van nick" }, { "C_MONOLOGUE", "spreekt veel monologen" } }, { /* Russian language */ /* contributed by kamikaze */ { "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 */ { "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 */ char *L(char *key) { int i; for (i=1;i<=NBKEYS;i++) if (strcmp(key,keys[language][i][0])==0) return(keys[language][i][1]); fprintf(stderr,"unknown language key: %s\n",key); return(""); } /* Variables */ 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,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 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; int nbusers=0; int maxusers=BASEUSERS; struct { char nick[MAXNICKLENGTH]; char url[MAXLINELENGTH]; char shorturl[MAXQUOTELENGTH+1]; } urls[NBURLS]; int nburls=0; struct { char nick[MAXNICKLENGTH]; char topic[MAXQUOTELENGTH+1]; } topics[NBTOPICS]; int nbtopics=0; struct { int lines; int hours[4]; } lastdays[31], lastweeks[31], lastmonths[31]; int days=0; char currday[16]; int currwday=-1, currmon=-1; int hours[24*4]; int lines=0; struct letter { int nb; struct letter *next[26]; } words; struct { int nb; 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) //#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; 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 n; else message++; pos=&words; while (isletter(*message)) { c=lowercase(*message)-'a'; 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; } pos=pos->next[(int)c]; message++; } pos->nb++; n++; } return n; } char tempword[MAXLINELENGTH]; void bestwords(struct letter pos,int cur) { int i,j; if ((cur>=MINWORDLENGTH)&&(pos.nb>topwords[NBWORDS-1].nb)) { for (i=0;pos.nbi;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<26;i++) if (pos.next[i]!=NULL) { tempword[cur]='a'+i; bestwords(*(pos.next[i]),cur+1); } 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.nbi;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; for (i=0;i<26;i++) if (pos->next[i]!=NULL) { freewords(pos->next[i]); free(pos->next[i]); (*pos).next[i]=NULL; } } void printhtml(FILE *fic,char *string) /* replace < and > by < and > */ { while (*string!='\0') { switch (*string) { case '<':fprintf(fic,"<"); break; case '>':fprintf(fic,">"); break; case '&':fprintf(fic,"&"); break; default:fprintf(fic,"%c",*string); break; } string++; } return; } int dichotomic(char *nick) { int i,j,start=0,end=nbusers-1,middle; while (start<=end) { middle=(start+end)/2; if (strcmp(nick,users[middle].nick)>0) start=middle+1; else end=middle-1; } if (strcmp(nick,users[start].nick)!=0) { nbusers++; 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;j0;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; char line[MAXLINELENGTH]; int pos; int i,j; char *nick,*message; int nickstart; 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=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("--- Log opened",line,14)==0) /* --- Log opened Wed May 01 00:00 2002 */ { if (debug==2) fprintf(stderr, "log %s opened, ", logfile); day_changed(line+15); } if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */ { if (debug==2) fprintf(stderr, "within log file, "); day_changed(line+16); } else { /* 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 */ { for (i=strlen(line);line[i]!=' ';i--); nick=&line[i+1]; users[dichotomic(nick)].counters[D_MODE]++; } else if (strncmp("-!-",&line[timelen],3)==0) /* 00:00 -!- Nick something... */ { 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[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 the message */ { /* * 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 '&': 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]; } /* 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]++; } // Fetch a random message, messages between 25 and 70 chars are // preferred (pisg-style, gets "better" quotes) // if (rand()%users[i].lines==0) { int len = strlen(message); // if we have a "good" quote, use it if ( len > 25 && len < 70 ) { strncpy(users[i].quote,message,MAXQUOTELENGTH); } else { int len2 = strlen(users[i].quote); if ( !(len2 > 25 && len2 < 70 )) { strncpy(users[i].quote,message,MAXQUOTELENGTH); } } } if (strncmp("http://",message,7)==0) { users[i].counters[D_URL]++; for (i=0;(message[i]!=' ') && (i=0)) { if (users[i].temp>users[user].temp) /* for nick alias, keep the random quote of the most used nick */ { strcpy(users[user].quote,users[i].quote); 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"); 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\n\n"); fprintf(fic,"\n\n",VERSION,URL); fprintf(fic,"\n\n\n"); fprintf(fic,L("HEADER"),channel,maintainer); fprintf(fic,"\n\n",L("CHARSET")); if (refresh_time) fprintf(fic,"\n",refresh_time); strcpy(line, theme); subtheme=strtok(line,","); fprintf(fic,"\n",subtheme,subtheme); while ((subtheme=strtok(NULL,","))!=NULL) fprintf(fic,"\n",subtheme,subtheme); fprintf(fic,"\n\n"); fprintf(fic,"\n\n"); } else { if ((sfic=fopen(header,"rt"))==NULL) { fprintf(stderr,"can't open header file \"%s\"\n",header); exit(1); } while ((temp=fread(line,1,MAXLINELENGTH,sfic))) fwrite(line,temp,1,fic); fclose(sfic); } fprintf(fic,"
\n\n
\n

"); fprintf(fic,L("HEADER"),channel,maintainer); fprintf(fic,"

\n

\n%s

\n
\n\n",ctime(&debut)); /* legend */ fprintf(fic,"
\n

%s

\n\n\n",L("LEGEND")); for (i=0;i<4;i++) fprintf(fic,"\n",i+1,L("HOURS"),i*6,i*6+5); fprintf(fic,"\n
%s %d-%d
\n
\n\n"); if (months) { /* last months */ fprintf(fic,"
\n

%s

\n\n\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,"\n"); } fprintf(fic,"\n\n"); for (i=30;i>=0;i--) fprintf(fic,"\n",i); fprintf(fic,"\n
%d",lastmonths[i].lines); for (j=0;j<4;j++) if (lastmonths[i].hours[j]!=0) fprintf(fic,"
",j+1,150*lastmonths[i].hours[j]/max); fprintf(fic,"
%d
\n
\n\n"); } if (weeks) { /* last weeks */ fprintf(fic,"
\n

%s

\n\n\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,"\n"); } fprintf(fic,"\n\n"); for (i=30;i>=0;i--) fprintf(fic,"\n",i); fprintf(fic,"\n
%d",lastweeks[i].lines); for (j=0;j<4;j++) if (lastweeks[i].hours[j]!=0) fprintf(fic,"
",j+1,150*lastweeks[i].hours[j]/max); fprintf(fic,"
%d
\n
\n\n"); } /* last days */ fprintf(fic,"
\n

%s

\n\n\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,"\n"); } fprintf(fic,"\n\n"); for (i=30;i>=0;i--) fprintf(fic,"\n",i); fprintf(fic,"\n
%d",lastdays[i].lines); for (j=0;j<4;j++) if (lastdays[i].hours[j]!=0) fprintf(fic,"
",j+1,150*lastdays[i].hours[j]/max); fprintf(fic,"
%d
\n
\n\n"); /* top hours */ fprintf(fic,"
\n

%s

\n\n\n",L("TOPHOURS")); max=-1; 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,"\n"); } else for (i=0;i<24;i++) { fprintf(fic,"\n"); } fprintf(fic,"\n\n"); for (i=0;i<24;i++) if (quarter) fprintf(fic,"\n",i); else fprintf(fic,"\n",i); fprintf(fic,"\n
"); if (hours[i]!=0) fprintf(fic,"
",i/4/6+1,150*hours[i]/max); fprintf(fic,"
%.1f%%",lines!=0?(float)100*hours[i]/lines:0); if (hours[i]!=0) fprintf(fic,"
",i/6+1,150*hours[i]/max); fprintf(fic,"
%d%d
\n
\n\n"); /* top users */ fprintf(fic,"
\n

%s

\n",L("TOPUSERS")); switch (ranking) { case 0: fprintf(fic,"\n\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,"
%s%s%s%s%s
\n\n",L("NICK"),"rank",L("HOURS"),L("AVGLETTERS"),L("QUOTE")); break; } if (photos) fprintf(fic,""); fprintf(fic,""); for (i=1;i<=NBUSERS;i++) { user=-1; max=0; switch (ranking) { case 0: for (j=0;jmax) max=users[user=j].lines; break; case 1: for (j=0;jmax) max=users[user=j].words; break; case 2: for (j=0;jmax) max=users[user=j].letters; break; } if (user!=-1) { switch (ranking) { case 0: fprintf(fic,""); if (photos && users[user].photo!=NULL) { if (photo_size) fprintf(fic,"",users[user].photo,users[user].photo,photo_size,photo_size); else fprintf(fic,"",users[user].photo); } fprintf(fic,"\n"); users[user].lines=-1; users[user].words=-1; users[user].letters=-1; } } fprintf(fic,"
%s%s%s%s%s
%d%s%d",i,users[user].nick,users[user].lines); break; case 1: fprintf(fic,"
%d%s%d",i,users[user].nick,users[user].words); break; case 2: fprintf(fic,"
%d%s%d",i,users[user].nick,users[user].letters); break; } for (j=0;j<4;j++) if (users[user].hours[j]!=0) fprintf(fic,"
",j+1,100*users[user].hours[j]/users[user].lines); fprintf(fic,"
%d
\"",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,"\"\"\"\"\"
\n"); temp=0; for (i=0;i<=nbusers;i++) if (users[i].lines>=0) temp++; if (temp>0) { fprintf(fic,"

"); fprintf(fic,L("OTHERS"),temp); fprintf(fic,"

\n"); } fprintf(fic,"
\n\n"); /* top users by time */ fprintf(fic,"
\n

%s

\n",L("TOPUSERSTIME")); fprintf(fic,"\n"); for (i=0;i<4;i++) fprintf(fic,"",L("HOURS"),i*6,i*6+5); fprintf(fic,"\n"); for (i=1;i<=NBUSERSTIME;i++) { fprintf(fic,"",i); for (j=0;j<4;j++) { user=-1; max=0; for (k=0;kmax) max=users[user=k].hours[j]; if (user!=-1) { fprintf(fic,"",users[user].nick,users[user].hours[j]); users[user].hours[j]=-1; } else fprintf(fic,""); } fprintf(fic,"\n"); } fprintf(fic,"
%s %d-%d
%d%s%d
\n
\n\n"); /* random topics */ fprintf(fic,"
\n

%s

\n",L("RANDTOPICS")); fprintf(fic,"\n\n",L("CHANGEDBY"),L("NEWTOPIC")); for (i=nbtopics=0;i--) { fprintf(fic,"\n"); } fprintf(fic,"
%s%s
%s\"",topics[i].nick); printhtml(fic,topics[i].topic); fprintf(fic,"\"
\n
\n\n"); /* random urls */ fprintf(fic,"
\n

%s

\n",L("RANDURLS")); fprintf(fic,"\n\n",L("POSTEDBY"),L("POSTEDURL")); for (i=nburls=0;i--) { fprintf(fic,"\n"); } fprintf(fic,"
%s%s
%s\""); printhtml(fic,urls[i].shorturl); fprintf(fic,"\"
\n
\n\n"); /* top words */ if (top_words) { fprintf(fic,"
\n

%s

\n",L("TOPWORDS")); fprintf(fic,"\n\n",L("WORD"),L("OCCURRENCES")); for (i=0;i\n",i+1,topwords[i].word,topwords[i].nb); fprintf(fic,"
%s%s
%d\"%s\"%d
\n
\n\n"); } /* big numbers */ fprintf(fic,"
\n

%s

\n",L("BIGNUMBERS")); fprintf(fic,"\n\n",L("NICK"),L("NUMBERS"),L("NBLINES")); for (i=0;imax) max=users[user=j].counters[i]; if (user!=-1) fprintf(fic,"",users[user].nick,L(counters[i]),users[user].counters[i]); } fprintf(fic,"
%s%s%s
%s%s%d
\n
\n\n"); /* footer */ fprintf(fic,"
\n

"); fprintf(fic,L("TIME"),totallines,days,(int)(time(NULL)-debut)); fprintf(fic,"

\n

%s irssistats %s

\n",L("FOOTER"),URL,VERSION); if (w3c_link) { fprintf(fic,"

\n\"Valid\n"); fprintf(fic,"\"Valid\n

\n"); } fprintf(fic,"
\n\n"); /* logo*/ if (logo) fprintf(fic,"
\n\n"); /* end */ fprintf(fic,"
\n\n"); if (strcmp("none",footer)==0) { fprintf(fic,"\n\n\n"); } else { if ((sfic=fopen(footer,"rt"))==NULL) { fprintf(stderr,"can't open footer file \"%s\"\n",footer); exit(1); } while ((temp=fread(line,1,MAXLINELENGTH,sfic))) fwrite(line,temp,1,fic); fclose(sfic); } fclose(fic); } 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,j; if (configfile!=NULL) { if ((fic=fopen(configfile,"rt"))==NULL) { fprintf(stderr,"can't open config file : \"%s\"\n",configfile); exit(1); } } else { snprintf(line,MAXLINELENGTH-1,"%s/.irssistats",getenv("HOME")); line[MAXLINELENGTH-1]='\0'; if ((fic=fopen(line,"rt"))==NULL) if ((fic=fopen(GLOBALCONF,"rt"))==NULL) { 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); } } while (fgets(line,MAXLINELENGTH,fic)) { configlines++; if (*line!=';' && *line!='#' && *line!='/' && *line!='-' && *line!='\n') { if ((sscanf(line,"%s : %s\n",(char *)&keyword,(char *)&value))!=2) { fprintf(stderr,"error in config file : each line must have the format \"keyword : value\" (line %d)\n",configlines); exit(1); } if (strcmp("debug",keyword)==0) { if (strcmp("none",value)==0) debug=0; else if (strcmp("normal",value)==0) debug=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 if (strcmp("channel",keyword)==0) { if (debug==2) fprintf(stderr,"setting channel name to \"%s\"\n",value); strcpy(channel,value); } else if (strcmp("maintainer",keyword)==0) { if (debug==2) fprintf(stderr,"setting maintainer to \"%s\"\n",value); strcpy(maintainer,value); } else if (strcmp("language",keyword)==0) { if (debug==2) fprintf(stderr,"setting language to \"%s\"\n",value); for (i=0;i