version 0.5 v0.5
authorAntoine Jacquet <royale@zerezo.com>
Sat, 6 Dec 2003 23:00:00 +0000 (00:00 +0100)
committerAntoine Jacquet <royale@zerezo.com>
Sat, 6 Dec 2003 23:00:00 +0000 (00:00 +0100)
* configuration file
* it is now possible to build multiple stats in one run
* customizable header and footer
* now produces XHTML with CSS templates as suggested by some users
* "grayscale" and "pisg" theme were added
* italian support (thank you Coviello Giuseppe)
* dutch support and BSD include patch (thank you Jeroen Ubbink)
* patch nickmode (thank you Philipp Haegi)

38 files changed:
COPYING [changed mode: 0755->0644]
Makefile [changed mode: 0755->0644]
README [changed mode: 0755->0644]
data/blue.css [new file with mode: 0644]
data/dark.css [new file with mode: 0644]
data/default.css [new file with mode: 0644]
data/grayscale.css [new file with mode: 0644]
data/h1.png [moved from pix/h1.png with 100% similarity, mode: 0644]
data/h2.png [moved from pix/h2.png with 100% similarity, mode: 0644]
data/h3.png [moved from pix/h3.png with 100% similarity, mode: 0644]
data/h4.png [moved from pix/h4.png with 100% similarity, mode: 0644]
data/hm.png [moved from pix/hm.png with 100% similarity, mode: 0644]
data/irssistats_black.png [moved from pix/irssistats_black.png with 100% similarity, mode: 0644]
data/irssistats_white.png [moved from pix/irssistats_white.png with 100% similarity, mode: 0644]
data/namour.css [new file with mode: 0644]
data/pisg.css [new file with mode: 0644]
data/pisg_blue-h.png [new file with mode: 0644]
data/pisg_blue-v.png [new file with mode: 0644]
data/pisg_green-h.png [new file with mode: 0644]
data/pisg_green-v.png [new file with mode: 0644]
data/pisg_red-h.png [new file with mode: 0644]
data/pisg_red-v.png [new file with mode: 0644]
data/pisg_yellow-h.png [new file with mode: 0644]
data/pisg_yellow-v.png [new file with mode: 0644]
data/v1.png [moved from pix/v1.png with 100% similarity, mode: 0644]
data/v2.png [moved from pix/v2.png with 100% similarity, mode: 0644]
data/v3.png [moved from pix/v3.png with 100% similarity, mode: 0644]
data/v4.png [moved from pix/v4.png with 100% similarity, mode: 0644]
data/valid-css.png [new file with mode: 0644]
data/valid-xhtml10.png [new file with mode: 0644]
data/vm.png [moved from pix/vm.png with 100% similarity, mode: 0644]
data/zeduel.css [new file with mode: 0644]
data/zerezo.css [new file with mode: 0644]
irssistats.1 [deleted file]
irssistats.c [changed mode: 0755->0644]
pix/valid-html401.gif [deleted file]
sample.configfile [new file with mode: 0644]
sample.nickfile [moved from sample.nickfile.txt with 100% similarity, mode: 0644]

diff --git a/COPYING b/COPYING
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index e6e091b..aae279c
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,7 @@
 PRE = /usr/local
 BIN = $(PRE)/bin
-PIX = $(PRE)/share/irssistats/pix
+DAT = $(PRE)/share/irssistats/data
 DOC = $(PRE)/doc/irssistats
-MAN = $(PRE)/man/man1
 
 irssistats:irssistats.c
        gcc -o irssistats irssistats.c
@@ -11,13 +10,11 @@ clean:
        rm -f irssistats 
 
 install:irssistats
-       mkdir -p $(BIN) $(PIX) $(DOC) $(MAN)
+       mkdir -p $(BIN) $(DAT) $(DOC)
        cp -f irssistats $(BIN)
-       cp -f pix/* $(PIX)
-       cp -f COPYING README sample.nickfile.txt $(DOC)
-       cp -f irssistats.1 $(MAN)
+       cp -f data/* $(DAT)
+       cp -f COPYING README sample.nickfile sample.configfile $(DOC)
 
 uninstall:
        rm -f $(BIN)/irssistats
-       rm -rf $(PIX) $(DOC)
-       rm -f $(MAN)/irssistats.1
+       rm -rf $(DAT) $(DOC)
diff --git a/README b/README
old mode 100755 (executable)
new mode 100644 (file)
index 1f4c63d..ebba4e7
--- a/README
+++ b/README
@@ -1,14 +1,18 @@
-irssistats 0.44
+irssistats 0.5
 site: http://royale.zerezo.com/irssistats/
 mail: royale@zerezo.com
 
 install:
 make
-cp pix/* /path/to/webdir/
+cp data/* /path/to/webdir/
 
 usage:
-cat /path/to/file.log | ./irssistats \#channel maintainer language theme [nickfile] > /path/to/webdir/index.html
-(don't forget to escape the '#' in the channel name)
+irssistats [/path/to/file.conf]
+
+configfile:
+Since version 0.5 of irssistats, all the options are located in a config file.
+This allow you to specify multiple channels to parse.
+Take a look at the "sample.configfile" in this package to know more about the options and their usage.
 
 nickfile:
 Since version 0.4 of irssistats, you can use a nickfile to specify nicks to join.
@@ -20,7 +24,7 @@ Examples :
   <NULL> ^bot\|royale$ : remove "bot|royale" from statistics
 The nickfile must not contain any comments.
 The <NULL> final nick will remove matching nicks from all statistics, except from "Some URLs" and "Some topics"...
-You can also take a look at the "sample.nickfile.txt" in this package.
+You can also take a look at the "sample.nickfile" in this package.
 
 links:
 http://torus.lnet.lut.fi/ircstats/
diff --git a/data/blue.css b/data/blue.css
new file mode 100644 (file)
index 0000000..17166ee
--- /dev/null
@@ -0,0 +1,133 @@
+/* Blue theme... */
+
+body {
+  background: #FFFFFF;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #000000;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #4444FF;
+}
+
+#irssistats A:hover {
+  color: #CCCCFF;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+  color: #8888FF;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+  color: #AAAAFF;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #CCCCFF;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #EEEEFF;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/data/dark.css b/data/dark.css
new file mode 100644 (file)
index 0000000..eac24ba
--- /dev/null
@@ -0,0 +1,135 @@
+/* Black background */
+
+body {
+  background: #000000;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #FFFFFF;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #AAAAFF;
+}
+
+#irssistats A:hover {
+  color: #FFAAAA;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+  color: #AAAAFF;
+       font-size: 20pt;
+  margin-bottom: 10px;
+}
+
+#irssistats h2 {
+  color: #FFAAAA;
+       font-size: 15pt;
+  margin-bottom: 5px;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #552222;
+       border: 1px #774444 solid;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #225522;
+       border: 1px #447744 solid;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/data/default.css b/data/default.css
new file mode 100644 (file)
index 0000000..88a2b0d
--- /dev/null
@@ -0,0 +1,125 @@
+/* White background (default theme) */
+
+body {
+  background: #FFFFFF;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #000000;
+       margin: 0;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #FFEEEE;
+       border: 1px #FFCCCC solid;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #EEEEEE;
+       border: 1px #CCCCCC solid;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/data/grayscale.css b/data/grayscale.css
new file mode 100644 (file)
index 0000000..7131eaa
--- /dev/null
@@ -0,0 +1,118 @@
+/* Grayscale theme */
+
+body {
+  background: #bbbbbb;
+  text-align: center;
+}
+
+#irssistats {
+  background: #dddddd;
+  border: 3px #777777 double;
+  margin: 20px 100px 20px 100px;
+}
+
+#irssistats_header, #irssistats_legend, #irssistats_lastdays, #irssistats_tophours, #irssistats_topusers, #irssistats_topuserstime, #irssistats_randtopics, #irssistats_randurls, #irssistats_topwords, #irssistats_bignumbers, #irssistats_footer {
+  background: #ffffff;
+  border: 1px #777777 dotted;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #000000;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #000000;
+}
+
+#irssistats A:hover {
+  color: #666666;
+  text-decoration: none;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+  color: #000000;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+  color: #555555;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  color: #ffffff;
+  background: #555555;
+}
+
+#irssistats td {
+       font-size: 8pt;
+  background: #ffffff;
+  border: 1px #cccccc dotted;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 6pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1, #irssistats div.v1 {
+       background: #000000;
+}
+
+#irssistats div.h2, #irssistats div.v2 {
+       background: #777777;
+}
+
+#irssistats div.h3, #irssistats div.v3 {
+       background: #aaaaaa;
+}
+
+#irssistats div.h4, #irssistats div.v4 {
+       background: #dddddd;
+}
+
+#irssistats div.hm, #irssistats div.vm {
+       background: #888888;
+}
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/h1.png
rename to data/h1.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/h2.png
rename to data/h2.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/h3.png
rename to data/h3.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/h4.png
rename to data/h4.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/hm.png
rename to data/hm.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/irssistats_black.png
rename to data/irssistats_black.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/irssistats_white.png
rename to data/irssistats_white.png
diff --git a/data/namour.css b/data/namour.css
new file mode 100644 (file)
index 0000000..b19ebcc
--- /dev/null
@@ -0,0 +1,133 @@
+/* Purple and Pink */
+
+body {
+  background: #9933CC;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #DDAAFF;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #CC99FF;
+}
+
+#irssistats A:hover {
+  color: #FFC8C8;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+  color: #FFC8C8;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+  color: #FFC8C8;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #550088;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #7711AA;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/data/pisg.css b/data/pisg.css
new file mode 100644 (file)
index 0000000..211ab04
--- /dev/null
@@ -0,0 +1,170 @@
+/* "pisg like" theme */
+
+body {
+  background: #dedeee;
+  text-align: center;
+}
+
+#irssistats {
+  width: 650px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#irssistats * {
+  font-family: Verdana, Arial, sans-serif;
+  font-size: 13px;
+  color: black;
+       margin: 0;
+}
+
+#irssistats a {
+     text-decoration: none;
+}
+
+#irssistats a:link {
+  color: #0b407a;
+}
+
+#irssistats a:visited {
+  color: #0b407a;
+}
+#irssistats a:hover {
+  text-decoration: underline;
+  color: #0b407a;
+}
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+  font-family: Tahoma, Arial, sans-serif;
+  font-size: 16px;
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+#irssistats h2 {
+  color: white;
+  font-weight: bold;
+  text-align: center;
+  background-color: #666699;
+  border: 1px #000000 solid;
+  padding: 2px;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+  background-color: #C8C8DD;
+  text-align: left;
+}
+
+#irssistats_lastdays th, #irssistats_tophours th {
+  font-weight: normal;
+  color: #000000;
+  background-color: #CCCCCC;
+  font-size: 10px;
+  text-align: center;
+}
+
+#irssistats td {
+  font-family: Verdana, Arial, sans-serif;
+  font-size: 13px;
+  color: black;
+  text-align: left;
+  background: #bcbcda;
+}
+
+#irssistats_legend td, #irssistats_lastdays td, #irssistats_tophours td {
+  text-align: center;
+  background: inherit;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+  font-family: "Arial narrow", Arial, sans-serif;
+  font-size: 9px;
+  color: black;
+  text-align: center;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats_topusers table, #irssistats_topuserstime table, #irssistats_randtopics table, #irssistats_randurls table, #irssistats_topwords table , #irssistats_bignumbers table {
+  width: 650px;
+}
+
+#irssistats div {
+       margin-bottom: 20px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('pisg_blue-h.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('pisg_green-h.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('pisg_yellow-h.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('pisg_red-h.png');
+}
+
+#irssistats div.hm {
+       background: #dd00dd;
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('pisg_blue-v.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('pisg_green-v.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('pisg_yellow-v.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('pisg_red-v.png');
+}
\ No newline at end of file
diff --git a/data/pisg_blue-h.png b/data/pisg_blue-h.png
new file mode 100644 (file)
index 0000000..fdad6b5
Binary files /dev/null and b/data/pisg_blue-h.png differ
diff --git a/data/pisg_blue-v.png b/data/pisg_blue-v.png
new file mode 100644 (file)
index 0000000..62877a7
Binary files /dev/null and b/data/pisg_blue-v.png differ
diff --git a/data/pisg_green-h.png b/data/pisg_green-h.png
new file mode 100644 (file)
index 0000000..1fe9224
Binary files /dev/null and b/data/pisg_green-h.png differ
diff --git a/data/pisg_green-v.png b/data/pisg_green-v.png
new file mode 100644 (file)
index 0000000..e5142b1
Binary files /dev/null and b/data/pisg_green-v.png differ
diff --git a/data/pisg_red-h.png b/data/pisg_red-h.png
new file mode 100644 (file)
index 0000000..2f52f4a
Binary files /dev/null and b/data/pisg_red-h.png differ
diff --git a/data/pisg_red-v.png b/data/pisg_red-v.png
new file mode 100644 (file)
index 0000000..cfe6c3b
Binary files /dev/null and b/data/pisg_red-v.png differ
diff --git a/data/pisg_yellow-h.png b/data/pisg_yellow-h.png
new file mode 100644 (file)
index 0000000..e92024f
Binary files /dev/null and b/data/pisg_yellow-h.png differ
diff --git a/data/pisg_yellow-v.png b/data/pisg_yellow-v.png
new file mode 100644 (file)
index 0000000..87bbde3
Binary files /dev/null and b/data/pisg_yellow-v.png differ
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/v1.png
rename to data/v1.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/v2.png
rename to data/v2.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/v3.png
rename to data/v3.png
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/v4.png
rename to data/v4.png
diff --git a/data/valid-css.png b/data/valid-css.png
new file mode 100644 (file)
index 0000000..9b2f596
Binary files /dev/null and b/data/valid-css.png differ
diff --git a/data/valid-xhtml10.png b/data/valid-xhtml10.png
new file mode 100644 (file)
index 0000000..2275ee6
Binary files /dev/null and b/data/valid-xhtml10.png differ
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from pix/vm.png
rename to data/vm.png
diff --git a/data/zeduel.css b/data/zeduel.css
new file mode 100644 (file)
index 0000000..941b36e
--- /dev/null
@@ -0,0 +1,133 @@
+/* Orange theme... */
+
+body {
+  background: #FFFFFF;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #000000;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #FF7700;
+}
+
+#irssistats A:hover {
+  color: #FF9A41;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+  color: #C05A00;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+  color: #FF7700;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #FF7700;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #FFEEEE;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/data/zerezo.css b/data/zerezo.css
new file mode 100644 (file)
index 0000000..d8d47a4
--- /dev/null
@@ -0,0 +1,135 @@
+/* Green theme... */
+
+body {
+  background: #000000;
+}
+
+#irssistats * {
+       font-family: Verdana, Arial, Helvetica, sans-serif;
+  color: #FFFFFF;
+       margin: 0;
+}
+
+#irssistats A {
+  color: #14F024;
+}
+
+#irssistats A:hover {
+  color: #FFFFFF;
+}
+
+#irssistats img {
+       border: 0;
+}
+
+#irssistats h1 {
+       font-size: 20pt;
+  margin-bottom: 10px;
+  color: #0CBA18;
+}
+
+#irssistats h2 {
+       font-size: 15pt;
+  margin-bottom: 5px;
+  color: #84DB8C;
+}
+
+#irssitats p {
+       font-size: 10pt;
+}
+
+#irssistats th {
+       font-size: 9pt;
+  background: #0B810B;
+       border: 1px #006600 solid;
+}
+
+#irssistats td {
+       font-size: 9pt;
+  background: #085D10;
+       border: 1px #003300 solid;
+}
+
+#irssistats td.oneline {
+  width: 100px;
+}
+
+#irssistats small {
+       font-size: 7pt;
+}
+
+#irssistats table {
+  margin-left: auto;
+  margin-right: auto; 
+}
+
+#irssistats div {
+       padding: 10px;
+       margin: 10px;
+       text-align: center;
+}
+
+#irssistats div.h1, #irssistats div.h2, #irssistats div.h3, #irssistats div.h4, #irssistats div.hm {
+       float: left;
+       height: 15px;
+       margin: 0;
+       padding: 0;
+  border: 0;
+}
+
+#irssistats div.v1, #irssistats div.v2, #irssistats div.v3, #irssistats div.v4, #irssistats div.vm {
+       width: 15px;
+       margin: 0;
+       padding: 0;
+       border: 0;
+}
+
+#irssistats div.h1 {
+       background: #0000ff;
+  background: url('h1.png');
+}
+
+#irssistats div.h2 {
+       background: #00ff00;
+  background: url('h2.png');
+}
+
+#irssistats div.h3 {
+       background: #ffff00;
+  background: url('h3.png');
+}
+
+#irssistats div.h4 {
+       background: #ff0000;
+  background: url('h4.png');
+}
+
+#irssistats div.hm {
+       background: #ff00ff;
+  background: url('hm.png');
+}
+
+#irssistats div.v1 {
+       background: #0000ff;
+  background: url('v1.png');
+}
+
+#irssistats div.v2 {
+       background: #00ff00;
+  background: url('v2.png');
+}
+
+#irssistats div.v3 {
+       background: #ffff00;
+  background: url('v3.png');
+}
+
+#irssistats div.v4 {
+       background: #ff0000;
+  background: url('v4.png');
+}
+
+#irssistats div.vm {
+       background: #ff00ff;
+  background: url('vm.png');
+}
\ No newline at end of file
diff --git a/irssistats.1 b/irssistats.1
deleted file mode 100755 (executable)
index 2e7495c..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-.TH irssistats 1 23-Nov-2002 "version 0.44" irssistats
-
-.SH NAME
-irssistats - A tool to generate HTML IRC stats based on irssi logs.
-
-.SH SYNOPSIS
-cat /path/to/file.log | \fBirssistats\fP \fI\\#channel\fP \fImaintainer\fP \fIlanguage\fP \fItheme\fP \fI[nickfile]\fP > /path/to/webdir/index.html
-
-.SH DESCRIPTION
-\fBirssistats\fP is a tool that make HTML stats from \fIirssi\fP logfiles.
-.PP
-It works like a filter (it reads data in input and produces the HTML page on the output).
-.PP
-The statistics generated display many useful and funny informations about the channel.
-
-.SH USING IT
-First you need to copy the images needed for the HTML page :
-.PP
-.B cp /usr/share/irssistats/pix/* /path/to/webdir/
-.PP
-Now you can generate the statistics for your channel :
-.PP
-.B cat /path/to/file.log | irssistats \\\\#channel maintainer language theme [nickfile] > /path/to/webdir/index.html
-.PP
-The logfiles for \fIirssi\fP are usually located in "~/irclogs/network/channel.log"
-
-.SH COMMAND LINE OPTIONS
-All the options (except the nickfile) are mandatory and have to be set at the good place on the command line.
-.PP
-If you make any mistake on the command line, \fBirssistats\fP will remind you the usage.
-.PP
-Launching \fBirssistats\fP without any parameters is a good way to show the available options.
-.PP
-.TP 8
-.B \\\\#channel
-Specifies the name of the channel you are parsing. Don't forget to escape the '#' character in the channel name.
-.TP 8
-.B maintainer
-Nickname of the person generating the statistics (you !).
-.TP 8
-.B language
-Language you want to use to display the statistics (example : "en" for english).
-.TP 8
-.B theme
-Theme (colors) to use for the statistics (example : "default" for the default theme).
-.TP 8
-.B nickfile
-This is the only optional argument. Specifies an alias file for nicks. See Below.
-
-.SH NICKFILE
-Since version 0.4 of \fBirssistats\fP, you can use a nickfile to specify nicks to join.
-.PP
-Each line of the nickfile contains the final nick and a regular expression.
-.PP
-Examples :
-.TP 8
-.B royale ^[Rr]oyale
-join nicks starting with "Royale" or "royale" to the final nick "royale"
-.TP 8
-.B royale ^antoine$
-also join the nick "antoine" to the final nick "royale"
-.TP 8
-.B djakette [Dd]ja
-join any nick that contains "Dja" or "dja" to final nick "djakette"
-.TP 8
-.B <NULL> ^bot\\\\|royale$
-remove "bot|royale" from statistics
-.PP
-The nickfile must not contain any comments.
-.PP
-The <NULL> final nick will remove matching nicks from all statistics, except from "Some URLs" and "Some topics"...
-.PP
-You can also take a look at the "sample.nickfile.txt" in this package (in "/usr/share/doc/irssistats/").
-
-.SH SEE ALSO
-irssi(1)
-
-.SH INFORMATIONS
-You can find informations and updates of \fBirssistats\fP at \fIhttp://royale.zerezo.com/irssistats/\fP.
-.PP
-Report bugs to \fIroyale@zerezo.com\fP.
-
-.SH AUTHOR
-Antoine Jacquet <\fIroyale@zerezo.com\fP>
old mode 100755 (executable)
new mode 100644 (file)
index 832b239..ae6b2a8
@@ -1,15 +1,12 @@
-/* Usage: cat /path/to/file.log | ./irssistats \#channel maintainer language theme [nickfile] > /path/to/file.html */
+/* Usage: irssistats [/path/to/file.conf] */
 
+#include <sys/types.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <string.h>
 #include <regex.h>
 
-/* Options */
-#define REFRESH_TIME 3600
-#define W3C_LINK
-
 /* Config */
 #define MAXUSERS 10000
 #define MAXNICKLENGTH 50
@@ -23,7 +20,7 @@
 #define MINWORDLENGTH 5
 
 /* irssistats */
-#define VERSION "0.44"
+#define VERSION "0.5"
 #define URL "http://royale.zerezo.com/irssistats/"
 
 /* Counters */
@@ -44,7 +41,7 @@
 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 6
+#define NBLANGUAGES 8
 #define NBKEYS 38
 char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
 {
@@ -90,7 +87,7 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "C_MONOLOGUE",  "speaks a lot of monologues" }
   },
   { /* French language */
-    { "French",     "fr" },
+    { "French",       "fr" },
     { "HEADER",       "Statistiques de %s par %s" },
     { "LEGEND",       "L&eacute;gende" },
     { "LASTDAYS",     "Statistiques des derniers jours" },
@@ -297,10 +294,94 @@ char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and ab
     { "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 <giuseppecoviello@tin.it> <http://coviello.altervista.org> */
+    { "Italian",      "it" },
+    { "HEADER",       "Statistiche per il canale %s di %s" },
+    { "LEGEND",       "Legenda" },
+    { "LASTDAYS",     "Statistiche degli ultimi giorni" },
+    { "TOPHOURS",     "Statistiche in ore" },
+    { "TOPUSERS",     "Utenti pi&ugrave; 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 <crasp@blackbyte.nl> */
+    { "Dutch",        "nl" },
+    { "HEADER",       "Statistieken voor %s door %s" },
+    { "LEGEND",       "Legenda" },
+    { "LASTDAYS",     "Statistieken van de laatste dagen" },
+    { "TOPHOURS",     "Statistieken per uur" },
+    { "TOPUSERS",     "Meest actieve mensen" },
+    { "OTHERS",       "Er zijn nog %d niet in de top..." },
+    { "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 gegenereert 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" }
+  }  
 };
 
-int language;
+int language=0; /* default to english */
 
 char *L(char *key)
 {
@@ -310,99 +391,18 @@ char *L(char *key)
   return("");
 }
 
-/* Themes */
-#define NBTHEMES 6
-#define NBCOLORS 9
-char *colors[NBTHEMES][NBCOLORS+1][2]= /* first key used for theme name/description and abbreviation */
-{
-  { /* Default theme */
-    { "White background", "default" },
-    { "BGCOLOR", "#FFFFFF" },
-    { "TEXT",    "#000000" },
-    { "LINK",    "#0000EE" },
-    { "VLINK",   "#551A8B" },
-    { "ALINK",   "#FF0000" },
-    { "TITLE1",  "#000000" },
-    { "TITLE2",  "#000000" },
-    { "BGTABLE", "#EEEEEE" },
-    { "BGTITLE", "#FFEEEE" }
-  },
-  { /* Dark theme */
-    { "Black background", "dark" },
-    { "BGCOLOR", "#000000" },
-    { "TEXT",    "#FFFFFF" },
-    { "LINK",    "#AAAAFF" },
-    { "VLINK",   "#CCCCDD" },
-    { "ALINK",   "#FFAAAA" },
-    { "TITLE1",  "#AAAAFF" },
-    { "TITLE2",  "#FFAAAA" },
-    { "BGTABLE", "#225522" },
-    { "BGTITLE", "#552222" }
-  },
-  { /* zeRezo theme */
-    { "Green theme...", "zerezo" },
-    { "BGCOLOR", "#000000" },
-    { "TEXT",    "#FFFFFF" },
-    { "LINK",    "#14F024" },
-    { "VLINK",   "#0CBA18" },
-    { "ALINK",   "#FFFFFF" },
-    { "TITLE1",  "#0CBA18" },
-    { "TITLE2",  "#84DB8C" },
-    { "BGTABLE", "#085D10" },
-    { "BGTITLE", "#0B810B" }
-  },
-  { /* tit-namour theme */
-    { "Purple and Pink", "namour" },
-    { "BGCOLOR", "#9933CC" },
-    { "TEXT",    "#DDAAFF" },
-    { "LINK",    "#CC99FF" },
-    { "VLINK",   "#999999" },
-    { "ALINK",   "#FFC8C8" },
-    { "TITLE1",  "#FFC8C8" },
-    { "TITLE2",  "#FFC8C8" },
-    { "BGTABLE", "#7711AA" },
-    { "BGTITLE", "#550088" }
-  },
-  { /* zeDuel theme */
-    { "Orange theme...", "zeduel" },
-    { "BGCOLOR", "#FFFFFF" },
-    { "TEXT",    "#000000" },
-    { "LINK",    "#FF7700" },
-    { "VLINK",   "#C05A00" },
-    { "ALINK",   "#FF9A41" },
-    { "TITLE1",  "#C05A00" },
-    { "TITLE2",  "#FF7700" },
-    { "BGTABLE", "#FFEEEE" },
-    { "BGTITLE", "#FF7700" }
-  },
-  { /* Blue theme */
-    { "Blue theme...", "blue" },
-    { "BGCOLOR", "#FFFFFF" },
-    { "TEXT",    "#000000" },
-    { "LINK",    "#4444FF" },
-    { "VLINK",   "#8888FF" },
-    { "ALINK",   "#CCCCFF" },
-    { "TITLE1",  "#8888FF" },
-    { "TITLE2",  "#AAAAFF" },
-    { "BGTABLE", "#EEEEFF" },
-    { "BGTITLE", "#CCCCFF" }
-  }
-};
-
-int theme;
-
-char *T(char *color)
-{
-  int i;
-  for (i=1;i<=NBCOLORS;i++) if (strcmp(color,colors[theme][i][0])==0) return(colors[theme][i][1]);
-  fprintf(stderr,"unknown theme color: %s\n",color);
-  return("");
-}
-
 /* Variables */
 
-char *channel;
-char *maintainer;
+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";
+int refresh_time=0; /* 0 = disabled */
+int w3c_link=1; /* 0 = disabled */
+char header[MAXLINELENGTH]="none";
+char footer[MAXLINELENGTH]="none";
+int totallines=0;
+time_t debut;
 
 struct
 {
@@ -504,16 +504,27 @@ void bestwords(struct letter pos,int cur)
   tempword[cur]='\0';
 }
 
-void printhtml(char *string) /* replace < and > by &lt; and &gt; */
+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 &lt; and &gt; */
 {
   while (*string!='\0')
   {
     switch (*string)
     {
-      case '<':printf("&lt;"); break;
-      case '>':printf("&gt;"); break;
-      case '&':printf("&amp;"); break;
-      default:printf("%c",*string); break;
+      case '<':fprintf(fic,"&lt;"); break;
+      case '>':fprintf(fic,"&gt;"); break;
+      case '&':fprintf(fic,"&amp;"); break;
+      default:fprintf(fic,"%c",*string); break;
     }
     string++;
   }
@@ -553,288 +564,287 @@ int dichotomic(char *nick)
   return(start);
 }
 
-int main(int argc,char *argv[])
+void parse_log(char *logfile)
 {
-  int i,j,k;
-  int max,user,temp,hour;
-  int mononick,monolines;
-  time_t debut;
-  int totallines=0;
-  int pos=0;
-  char c;
-  char *nick,*message;
-  char line[MAXLINELENGTH];
   FILE *fic;
-  regex_t preg;
-  
-  /*** INIT ***/
-  
-  if ((argc<5) || (argc>6))
-  {
-    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]);
-    fprintf(stderr,"\nSupported themes :\n");
-    for (i=0;i<NBTHEMES;i++) fprintf(stderr,"%s = %s\n",colors[i][0][1],colors[i][0][0]);
-    return(1);
-  }
-  channel=argv[1];
-  maintainer=argv[2];
-  for (i=0;i<NBLANGUAGES;i++) if (strcmp(argv[3],keys[i][0][1])==0) { language=i; break; }
-  if (i==NBLANGUAGES)
-  {
-    fprintf(stderr,"Invalid language : %s\n",argv[3]);
-    return(1);
-  }
-  for (i=0;i<NBTHEMES;i++) if (strcmp(argv[4],colors[i][0][1])==0) { theme=i; break; }
-  if (i==NBTHEMES)
-  {
-    fprintf(stderr,"Invalid theme : %s\n",argv[4]);
-    return(1);
-  }
+  char line[MAXLINELENGTH];
+  int pos;
+  int i,j;
+  char *nick,*message;
+  int nickstart;
+  int mononick,monolines;
+  int temp,hour;
 
-  /*** LOG ***/
-  
-  srand(debut=time(NULL));
-  fprintf(stderr,"working on %s : ",channel);
-  while (!feof(stdin))
+  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)
   {
-    c=getchar();
-    line[pos++]=c;
-    if (pos>=MAXLINELENGTH) { fprintf(stderr,"line %d is too long\n",totallines); exit(1); }
-    if (c=='\n')
+    /* remove \n */
+    for (i=0;line[i]!=0;i++);
+    if (i>=MAXLINELENGTH-1) { fprintf(stderr,"line %d is too long\n",totallines); exit(1); }
+    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 */
+    {
+      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++;
+    }
+    else if (strncmp("-!- mode/",&line[6],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[6],3)==0) /* 00:00 -!- Nick something... */
     {
-      line[pos-1]='\0';
-      totallines++;
-      if (totallines%10000==0) { fprintf(stderr,"."); fflush(stderr); }
-      if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
+      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 */
       {
-        for (i=30;i>0;i--)
+        users[dichotomic(nick)].counters[D_TOPIC]++;
+        for (i=21;message[i]!=':';i++);
+        message=&message[i+2];
+        nbtopics++;
+        if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
         {
-          lastdays[i].lines=lastdays[i-1].lines;
-          for (j=0;j<4;j++) lastdays[i].hours[j]=lastdays[i-1].hours[j];
+          temp=nbtopics<=NBTOPICS?nbtopics-1:rand()%NBTOPICS;
+          strcpy(topics[temp].nick,nick);
+          strncpy(topics[temp].topic,message,MAXQUOTELENGTH);
         }
-        lastdays[0].lines=0;
-        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("was kicked from",message,15)==0) /* 00:00 -!- Nick was kicked from #channel by Nick [Reason] */
       {
-        for (i=strlen(line);line[i]!=' ';i--);
-        nick=&line[i+1];
-        users[dichotomic(nick)].counters[D_MODE]++;
+        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("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
+      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=10;line[i]!=' ';i++);
-        line[i]='\0';
-        nick=&line[10];
+        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 */
+      {
+        for (i=9;line[i]!=' ';i++);
+        nick=&line[9];
         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[6]=='<') || (line[7]=='*'))
+      else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
+                             /* 00:00 <>>?Nick<<> the personal message */
       {
-        line[2]='\0';
-        hour=atoi(line);
-        if (line[7]=='*') /* 00:00  * Nick the message */
-        {
-          for (i=9;line[i]!=' ';i++);
-          nick=&line[9];
-          message=&line[i+1];
-        }
-        else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
-                               /* 00:00 <>>?Nick<<> the personal message */
-        {
-          for (i=10;line[i]!='<';i++);
-          nick=&line[10];
-          if (line[9]=='>') nick++;
-          message=&line[i+5];
-        }
-        else /* 00:00 <?Nick> the message */
-        {
-          for (i=8;line[i]!='>';i++);
-          nick=&line[8];
-          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]++;
+        for (i=10;line[i]!='<';i++);
+        nick=&line[10];
+        if (line[9]=='>') 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;
         }
-        if (rand()%users[i].lines==0) strncpy(users[i].quote,message,MAXQUOTELENGTH);
-        if (strncmp("http://",message,7)==0)
+          
+        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))
         {
-          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);
-          }
+          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;
+      findwords(message);
     }
+    pos=0;
   }
-  fprintf(stderr," done\n");
-
-  bestwords(words,0);
+  fclose(fic);
+  if (debug) printf(" done\n");
+}
 
-  /*** ALIAS ***/
+void parse_nick(char *nickfile)
+{
+  FILE *fic;
+  int i,j;
+  regex_t preg;
+  char line[MAXLINELENGTH];
+  int user;
   
-  if (argc==6)
+  for (i=0;i<nbusers;i++) users[i].temp=users[i].lines;
+  if ((fic=fopen(nickfile,"rt"))==NULL) { fprintf(stderr,"can't open nick file \"%s\"\n",nickfile); exit(1); }
+  while (fscanf(fic,"%s",line)==1)
   {
-    for (i=0;i<nbusers;i++) users[i].temp=users[i].lines;
-    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); }
+    for (i=0;i<nbusers;i++) if ((i!=user) && (regexec(&preg,users[i].nick,0,0,0)==0) && (users[i].lines>=0))
     {
-      user=dichotomic(line);
-      fscanf(fic,"%s",line);
-      if (regcomp(&preg,line,0)!=0) { fprintf(stderr,"error in nick file"); exit(1); }
-      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].temp>users[user].temp) /* for nick alias, keep the random quote of the most used nick */
       {
-        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].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;
+        strcpy(users[user].quote,users[i].quote);
+        users[user].temp=users[i].temp;
       }
-      regfree(&preg);
+      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;
     }
-    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;
+    regfree(&preg);
   }
-  
-  /*** HTML ***/
+  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;
+}
 
+void gen_xhtml(char *xhtmlfile)
+{
+  FILE *fic;
+  FILE *sfic;
+  int i,j,k;
+  int user,max,temp;
+  char line[MAXLINELENGTH];
+  
+  if ((fic=fopen(xhtmlfile,"wt"))==NULL) { fprintf(stderr,"can't open xhtml file \"%s\"\n",xhtmlfile); exit(1); }
+  
   /* header */
-  printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n\n");
-  printf("<!-- Generated by irssistats %s : %s -->\n\n",VERSION,URL);
-  printf("<html>\n\n<head>\n<title>");
-  printf(L("HEADER"),channel,maintainer);
-  printf("</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n");
-#ifdef REFRESH_TIME
-  printf("<meta http-equiv=\"Refresh\" content=\"%d\">\n",REFRESH_TIME);
-#endif
-  printf("<base target=\"_blank\">\n</head>\n\n");
-  printf("<body bgcolor=\"%s\" text=\"%s\" link=\"%s\" vlink=\"%s\" alink=\"%s\">\n\n<center>\n\n<font color=\"%s\" size=\"+3\"><b>",T("BGCOLOR"),T("TEXT"),T("LINK"),T("VLINK"),T("ALINK"),T("TITLE1"));
-  printf(L("HEADER"),channel,maintainer);
-  printf("</b></font><br><br>\n%s<br>\n<br><br>\n\n",ctime(&debut));
+  if (strcmp("none",header)==0)
+  {
+    fprintf(fic,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n");
+    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");
+    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);
+    fprintf(fic,"</head>\n\n");
+    fprintf(fic,"<body>\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,"<div id=\"irssistats\">\n\n<div id=\"irssistats_header\">\n<h1>");
+  fprintf(fic,L("HEADER"),channel,maintainer);
+  fprintf(fic,"</h1>\n<p>\n%s</p>\n</div>\n\n",ctime(&debut));
 
   /* legend */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n<table bgcolor=\"%s\">\n<tr>\n",T("TITLE2"),L("LEGEND"),T("BGTABLE"));
-  for (i=0;i<4;i++) printf("<td><img src=\"h%d.png\" width=\"40\" height=\"15\" alt=\"\"></td><td> : %s %d-%d</td><td width=\"10\"></td>\n",i+1,L("HOURS"),i*6,i*6+5);
-  printf("</tr>\n</table>\n<br><br>\n\n");
+  fprintf(fic,"<div id=\"irssistats_legend\">\n<h2>%s</h2>\n<table>\n<tr>\n",L("LEGEND"));
+  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");
   
   /* last days */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n<table>\n<tr>\n",T("TITLE2"),L("LASTDAYS"));
+  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--)
   {
-    printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%d</font><br>",lastdays[i].lines);
-    for (j=0;j<4;j++) if (lastdays[i].hours[j]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\" alt=\"\"><br>",j+1,150*lastdays[i].hours[j]/max);
-    printf("</td>\n");
+    fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%d</small>",lastdays[i].lines); /* width=\"15\" */
+    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");
   }
-  printf("</tr>\n<tr>\n");
+  fprintf(fic,"</tr>\n<tr>\n");
   for (i=30;i>=0;i--)
-    printf("<td align=\"center\" valign=\"middle\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
-  printf("</tr>\n</table>\n<br><br>\n\n");
+    fprintf(fic,"<th>%d</th>\n",i);
+  fprintf(fic,"</tr>\n</table>\n</div>\n\n");
   
   /* top hours */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n<table>\n<tr>\n",T("TITLE2"),L("TOPHOURS"));
+  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++)
   {
-    printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%.1f%%</font><br>",lines!=0?(float)100*hours[i]/lines:0);
-    if (hours[i]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\" alt=\"\"><br>",i/6+1,150*hours[i]/max);
-    printf("</td>\n");
+    fprintf(fic,"<td align=\"center\" valign=\"bottom\"><small>%.1f%%</small>",lines!=0?(float)100*hours[i]/lines:0); /* width=\"15\" */
+    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");
   }
-  printf("</tr>\n<tr>\n");
+  fprintf(fic,"</tr>\n<tr>\n");
   for (i=0;i<24;i++)
-    printf("<td align=\"center\" valign=\"middle\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
-  printf("</tr>\n</table>\n<br><br>\n\n");
+    fprintf(fic,"<th>%d</th>\n",i);
+  fprintf(fic,"</tr>\n</table>\n</div>\n\n");
   
   /* top users */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("TOPUSERS"));
-  printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\" colspan=\"2\">%s</td><td bgcolor=\"%s\">%s</td>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NBLINES"),T("BGTITLE"),L("HOURS"),T("BGTITLE"),L("AVGLETTERS"),T("BGTITLE"),L("QUOTE"));
+  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"));
   for (i=1;i<=NBUSERS;i++)
   {
     user=-1;
@@ -842,33 +852,33 @@ int main(int argc,char *argv[])
     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\" alt=\"\">",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\" alt=\"\"></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");
+      fprintf(fic,"<tr><td>%d</td><td>%s</td><td>%d</td><td class=\"oneline\">",i,users[user].nick,users[user].lines);
+      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");
       users[user].lines=-1;
     }    
   }
-  printf("</table>\n");
+  fprintf(fic,"</table>\n");
   temp=0;
   for (i=0;i<=nbusers;i++) if (users[i].lines>=0) temp++;
   if (temp>0)
   {
-    printf("<br>");
-    printf(L("OTHERS"),temp);
-    printf("<br>\n");
+    fprintf(fic,"<p>");
+    fprintf(fic,L("OTHERS"),temp);
+    fprintf(fic,"</p>\n");
   }
-  printf("<br><br>\n\n");
+  fprintf(fic,"</div>\n\n");
   
   /* top users by time */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("TOPUSERSTIME"));
-  printf("<table>\n<tr><td></td>");
-  for (i=0;i<4;i++) printf("<td bgcolor=\"%s\" colspan=\"2\">%s %d-%d</td>",T("BGTITLE"),L("HOURS"),i*6,i*6+5);
-  printf("</tr>\n");
+  fprintf(fic,"<div id=\"irssistats_topuserstime\">\n<h2>%s</h2>\n",L("TOPUSERSTIME"));
+  fprintf(fic,"<table>\n<tr><th></th>");
+  for (i=0;i<4;i++) fprintf(fic,"<th colspan=\"2\">%s %d-%d</th>",L("HOURS"),i*6,i*6+5);
+  fprintf(fic,"</tr>\n");
   for (i=1;i<=NBUSERSTIME;i++)
   {
-    printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td>",T("BGTABLE"),i);
+    fprintf(fic,"<tr><td>%d</td>",i);
     for (j=0;j<4;j++)
     {
       user=-1;
@@ -876,65 +886,242 @@ int main(int argc,char *argv[])
       for (k=0;k<nbusers;k++) if (users[k].hours[j]>max) max=users[user=k].hours[j];
       if (user!=-1)
       {
-        printf("<td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td>",T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].hours[j]);
+        fprintf(fic,"<td>%s</td><td>%d</td>",users[user].nick,users[user].hours[j]);
         users[user].hours[j]=-1;
       }
-      else printf("<td></td><td></td>");
+      else fprintf(fic,"<td></td><td></td>");
     }
-    printf("</tr>\n");
+    fprintf(fic,"</tr>\n");
   }
-  printf("</table>\n<br><br>\n\n");
+  fprintf(fic,"</table>\n</div>\n\n");
 
   /* random topics */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("RANDTOPICS"));
-  printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("CHANGEDBY"),T("BGTITLE"),L("NEWTOPIC"));
+  fprintf(fic,"<div id=\"irssistats_randtopics\">\n<h2>%s</h2>\n",L("RANDTOPICS"));
+  fprintf(fic,"<table>\n<tr><th>%s</th><th>%s</th></tr>\n",L("CHANGEDBY"),L("NEWTOPIC"));
   for (i=nbtopics<NBTOPICS?nbtopics-1:NBTOPICS-1;i>=0;i--)
   {
-    printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"",T("BGTABLE"),topics[i].nick,T("BGTABLE"));
-    printhtml(topics[i].topic);
-    printf("\"</td></tr>\n");
+    fprintf(fic,"<tr><td>%s</td><td>\"",topics[i].nick);
+    printhtml(fic,topics[i].topic);
+    fprintf(fic,"\"</td></tr>\n");
   }
-  printf("</table>\n<br><br>\n\n");
+  fprintf(fic,"</table>\n</div>\n\n");
   
   /* random urls */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("RANDURLS"));
-  printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("POSTEDBY"),T("BGTITLE"),L("POSTEDURL"));
+  fprintf(fic,"<div id=\"irssistats_randurls\">\n<h2>%s</h2>\n",L("RANDURLS"));
+  fprintf(fic,"<table>\n<tr><th>%s</th><th>%s</th></tr>\n",L("POSTEDBY"),L("POSTEDURL"));
   for (i=nburls<NBURLS?nburls-1:NBURLS-1;i>=0;i--)
   {
-    printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"<a href=\"",T("BGTABLE"),urls[i].nick,T("BGTABLE"));
-    printhtml(urls[i].url);
-    printf("\">");
-    printhtml(urls[i].shorturl);
-    printf("</a>\"</td></tr>\n");
+    fprintf(fic,"<tr><td>%s</td><td>\"<a href=\"",urls[i].nick);
+    printhtml(fic,urls[i].url);
+    fprintf(fic,"\">");
+    printhtml(fic,urls[i].shorturl);
+    fprintf(fic,"</a>\"</td></tr>\n");
   }
-  printf("</table>\n<br><br>\n\n");
+  fprintf(fic,"</table>\n</div>\n\n");
   
   /* top words */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("TOPWORDS"));
-  printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("WORD"),T("BGTITLE"),L("OCCURRENCES"));
+  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) printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">\"%s\"</td><td bgcolor=\"%s\">%d</td></tr>\n",T("BGTABLE"),i+1,T("BGTABLE"),topwords[i].word,T("BGTABLE"),topwords[i].nb);
-  printf("</table>\n<br><br>\n\n");
+    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 */
-  printf("<font color=\"%s\" size=\"+1\"><b>%s</b></font><br><br>\n",T("TITLE2"),L("BIGNUMBERS"));
-  printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NUMBERS"),T("BGTITLE"),L("NBLINES"));
+  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"));
   for (i=0;i<NBCOUNTERS;i++)
   {
     user=-1;
     max=0;
     for (j=0;j<nbusers;j++) if (users[j].counters[i]>max) max=users[user=j].counters[i];
-    if (user!=-1) printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td></tr>",T("BGTABLE"),users[user].nick,T("BGTABLE"),L(counters[i]),T("BGTABLE"),users[user].counters[i]);
+    if (user!=-1) fprintf(fic,"<tr><td>%s</td><td>%s</td><td>%d</td></tr>",users[user].nick,L(counters[i]),users[user].counters[i]);
   }
-  printf("</table>\n<br><br>\n\n");
+  fprintf(fic,"</table>\n</div>\n\n");
   
   /* footer */
-  printf(L("TIME"),totallines,days,(int)(time(NULL)-debut));
-  printf("<br>\n%s <a href=\"%s\">irssistats %s</a>",L("FOOTER"),URL,VERSION);
-#ifdef W3C_LINK
-  printf("<br><br>\n\n<a href=\"http://validator.w3.org/check/referer\"><img src=\"valid-html401.gif\" border=\"0\" height=\"31\" width=\"88\"alt=\"Valid HTML 4.01!\"></a>");
-#endif
-  printf("\n\n</center>\n\n</body>\n\n</html>\n");
+  fprintf(fic,"<div id=\"irssistats_footer\">\n<p>");
+  fprintf(fic,L("TIME"),totallines,days,(int)(time(NULL)-debut));
+  fprintf(fic,"</p>\n<p>%s <a href=\"%s\">irssistats %s</a></p>\n",L("FOOTER"),URL,VERSION);
+  if (w3c_link)
+  {
+    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,"\n\n</body>\n\n</html>\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)
+{
+  FILE *fic;
+  char line[MAXLINELENGTH];
+  char keyword[MAXLINELENGTH];
+  char value[MAXLINELENGTH];
+  int configlines=0;
+  int i;
+  
+  if (configfile!=NULL)
+  {
+    if ((fic=fopen(configfile,"rt"))==NULL)
+    {
+      fprintf(stderr,"can't open config file : \"%s\"\n",configfile);
+      exit(1);
+    }
+  }
+  else
+  {
+    sprintf(line,"%s/.irssistats",getenv("HOME"));
+    if ((fic=fopen(line,"rt"))==NULL)
+      if ((fic=fopen("/etc/irssistats.conf","rt"))==NULL)
+      {
+        fprintf(stderr,"can't find config file : \"%s\" nor \"/etc/irssistats.conf\"\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<NBLANGUAGES;i++) if (strcmp(value,keys[i][0][1])==0) { language=i; break; }
+        if (i==NBLANGUAGES)
+        {
+          fprintf(stderr,"Invalid language : %s\n",value);
+          fprintf(stderr,"Supported languages :\n");
+          for (i=0;i<NBLANGUAGES;i++) fprintf(stderr,"%s = %s\n",keys[i][0][1],keys[i][0][0]);
+          exit(1);
+        }
+      }
+      else
+      
+      if (strcmp("theme",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting theme to \"%s\"\n",value);
+        strcpy(theme,value);
+      }
+      else
+      
+      if (strcmp("refresh_time",keyword)==0)
+      {
+        refresh_time=atoi(value);
+        if (debug==2) fprintf(stderr,"setting refresh_time to \"%d\"\n",refresh_time);
+      }
+      else
+      
+      if (strcmp("w3c_link",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting w3c_link to \"%s\"\n",value);
+        if (strcmp("no",value)==0) w3c_link=0;
+        else if (strcmp("yes",value)==0) w3c_link=1;
+        else { fprintf(stderr,"unknown value for \"w3c_link\" option, must be \"yes\" or \"no\"\n"); exit(1); }
+      }
+      else
+      
+      if (strcmp("header",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting header to \"%s\"\n",value);
+        strcpy(header,value);
+      }
+      else
+      
+      if (strcmp("footer",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"setting footer to \"%s\"\n",value);
+        strcpy(footer,value);
+      }
+      else
+      
+      if (strcmp("input",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"parsing log file \"%s\"\n",value);
+        parse_log(value);
+      }
+      else
+      
+      if (strcmp("nickfile",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"nick alias using file \"%s\"\n",value);
+        parse_nick(value);
+      }
+      else
+      
+      if (strcmp("output",keyword)==0)
+      {
+        if (debug==2) fprintf(stderr,"generating xhtml file \"%s\"\n",value);
+        bestwords(words,0);
+        gen_xhtml(value);
+        
+        /* reset variables */
+        nbusers=0;
+        nburls=0;
+        nbtopics=0;
+        days=0;
+        for (i=0;i<24;i++) hours[i]=0;
+        lines=0;
+        freewords(&words);
+        for (i=0;i<NBWORDS;i++) topwords[i].nb=0;
+        totallines=0;
+        debut=time(NULL);
+      }
+      
+      else { 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[])
+{
+  srand(debut=time(NULL));
+  if (argc==1) parse_config(NULL);
+  else if (argc==2) parse_config(argv[1]);
+  else
+  {
+    fprintf(stderr,"Usage : %s [/path/to/file.conf]\n",argv[0]);
+    fprintf(stderr,"Version : irssistats %s\n",VERSION);
+    exit(1);
+  }
   return(0);
 }
diff --git a/pix/valid-html401.gif b/pix/valid-html401.gif
deleted file mode 100755 (executable)
index 1270561..0000000
Binary files a/pix/valid-html401.gif and /dev/null differ
diff --git a/sample.configfile b/sample.configfile
new file mode 100644 (file)
index 0000000..d618512
--- /dev/null
@@ -0,0 +1,79 @@
+# This is the configuration file for irssistats.
+# The path to this file can be given on the command line : irssistats /path/to/irssistats.conf
+# If no configuration file is given, irssistats looks for files ~/.irssistats.conf or then /etc/irssistats.conf
+# Lines starting by ; # -- or // are ignored (comments).
+# This file is read sequencially, so it acts like a script.
+# Each option keyword is case sensitive, and you must put separators around the ':' character.
+# Blank lines must not contain any spaces !
+# Each option keeps its value until erased by another value.
+# IMPORTANT : the order of options to parse a channel must allways be "input" THEN "nickfile" THEN "output".
+
+# Allows you to display debugging informations.
+# Values : normal / verbose / none
+# Default : normal
+debug : verbose
+
+# Specifies the name of the channel you are parsing.
+channel : #zerezo
+
+# Nickname of the person generating the statistics (you !).
+maintainer : royale
+
+# Language you want to use to display the statistics
+# Values : fr en de du es it fi
+# Default : en
+language : fr
+
+# Theme (colors) to use for the statistics
+# In fact this is the name of the CSS file to include.
+# This option has no effect if you use a custom header : you'll have to include the CSS yourself.
+theme : orange
+
+# Specifies the refresh time in seconds (0 to disable)
+# This option has no effect if you use a custom header : you'll have to include the refresh code yourself.
+# Default : 3600
+refresh_time : 0
+
+# Set this to "no" if you don't want the W3C logo.
+# Default : yes
+w3c_link : no
+
+# Use your custom header file (HTML code between <!DOCTYPE... and <body> included)
+header : /path/to/header.html
+
+# Use your custom footer file (HTML code between </body> and </html> included)
+footer : /path/to/footer.html
+
+# This allow you to parse a file.
+# Note that irssistats will really parse the file as soon as it reads this option.
+input : /path/to/#channel1.log
+
+# Let's parse another log.
+# Note that this will merge "#channel and "#channel2" statistics...
+# This is usefull if you splitted your channel file
+input : /path/to/#newchannel1.log
+
+# This allow you to group nick using a nickfile.
+# Note that irssistats will really merge the nicks as soon as it reads this option.
+nickfile : /path/to/nickfile1.txt
+
+# This allow you to generate the HTML file.
+# Note that irssistats will really generate the HTML file as soon as it reads this option.
+output : /path/to/channel1.html
+
+# Change some options
+language : en
+debug : none
+
+# Do not use custom header and footer anymore
+header : none
+footer : none
+
+# Another chan without nickfile
+input : /path/to/#channel2.log
+output : /path/to/channel2.html
+
+# Another chan with nickfile
+input : /path/to/#channel3.log
+nickfile : /path/to/nickfile3.txt
+output : /path/to/channel3.html
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from sample.nickfile.txt
rename to sample.nickfile