aboutsummaryrefslogtreecommitdiffstats
path: root/testing/eggdrop/logs2html.mod.patch
diff options
context:
space:
mode:
authorCarlo Landmeter <clandmeter@gmail.com>2009-03-28 10:09:12 +0000
committerCarlo Landmeter <clandmeter@gmail.com>2009-03-28 10:09:12 +0000
commit2ea272f408294b5d9be27c8a9033502f9531a861 (patch)
tree13ba4e619dcac2bf516e398a2e7c45b02bdf8af5 /testing/eggdrop/logs2html.mod.patch
parentc2b5f896c7b41766184e5c918672c68e17493ad4 (diff)
testing/eggdrop: added log2html and gseen. fixed deps.
Diffstat (limited to 'testing/eggdrop/logs2html.mod.patch')
-rw-r--r--testing/eggdrop/logs2html.mod.patch2404
1 files changed, 2404 insertions, 0 deletions
diff --git a/testing/eggdrop/logs2html.mod.patch b/testing/eggdrop/logs2html.mod.patch
new file mode 100644
index 00000000000..8ea2e94e629
--- /dev/null
+++ b/testing/eggdrop/logs2html.mod.patch
@@ -0,0 +1,2404 @@
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/Makefile eggdrop1.6.19/src/mod/logs2html.mod/Makefile
+--- src/mod/logs2html.mod/Makefile 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/Makefile 2009-03-28 01:32:21.000000000 +0000
+@@ -0,0 +1,42 @@
++# Makefile for src/mod/logs2html.mod/
++
++srcdir = .
++
++
++doofus:
++ @echo ""
++ @echo "Let's try this from the right directory..."
++ @echo ""
++ @cd ../../../ && make
++
++static: ../logs2html.o
++
++modules: ../../../logs2html.$(MOD_EXT)
++
++../logs2html.o:
++ $(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c $(srcdir)/logs2html.c
++ @rm -f ../logs2html.o
++ mv logs2html.o ../
++
++../../../logs2html.$(MOD_EXT): ../logs2html.o
++ $(LD) -o ../../../logs2html.$(MOD_EXT) ../logs2html.o
++ $(STRIP) ../../../logs2html.$(MOD_EXT)
++
++depend:
++ $(CC) $(CFLAGS) $(CPPFLAGS) -MM $(srcdir)/logs2html.c > .depend
++
++clean:
++ @rm -f .depend *.o *.$(MOD_EXT) *~
++distclean: clean
++
++#safety hash
++../logs2html.o: .././logs2html.mod/logs2html.c \
++ ../../../src/mod/module.h ../../../src/main.h ../../../src/lang.h \
++ ../../../src/eggdrop.h ../../../src/flags.h ../../../src/proto.h \
++ ../../../lush.h ../../../src/misc_file.h ../../../src/cmdt.h \
++ ../../../src/tclegg.h ../../../src/tclhash.h ../../../src/chan.h \
++ ../../../src/users.h ../../../src/compat/compat.h \
++ ../../../src/compat/inet_aton.h \
++ ../../../src/compat/snprintf.h ../../../src/compat/memset.h \
++ ../../../src/compat/memcpy.h ../../../src/compat/strcasecmp.h \
++ ../../../src/compat/strftime.h ../../../src/mod/modvals.h
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/chan.list eggdrop1.6.19/src/mod/logs2html.mod/chan.list
+--- src/mod/logs2html.mod/chan.list 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/chan.list 2009-03-28 01:43:40.000000000 +0000
+@@ -0,0 +1,22 @@
++# Add your channels here. The format is:
++# addlogs2htmlchan channel output-path main-page-name main-page-title logs-page-prefix logs-page-title
++# channel - your channel which logs you want to convert
++# output-path - your ftp path, where converted files will be put
++# (don't forget to check settings to be sure bot have
++# permision write to the path you specify)
++# main-page-name - name of your mainpage (i.e. page with calendar) for
++# this channel
++# main-page-title - your mainpage title for this channel (will be shown
++# as the caption of the web page in your browser and as
++# the title of calendar)
++# logs-page-prefix - your logs page name (prefix) for this channel.
++# Resulting name'll be 'logs-page-prefixYYmmdd'
++# logs-page-title - your logs page title for this channel (will be shown
++# as the caption of the web page in your browser)
++# Example:
++# addlogs2htmlchan "#MyChan" "logs" "index" "Logs of MyChan" "mychan" "Log of MyChan"
++#
++# Note: expression "logs2html" MUST be one line (i.e. without linefeeds
++# and carrige returns) and every parameter in the expression MUST be enclosed
++# with ".
++
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/fileoperations.c eggdrop1.6.19/src/mod/logs2html.mod/fileoperations.c
+--- src/mod/logs2html.mod/fileoperations.c 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/fileoperations.c 2009-03-28 01:45:19.000000000 +0000
+@@ -0,0 +1,142 @@
++/*
++ * fileoperations.c -- part of logs2html.mod
++ *
++ * Written by Fedotov Alexander aka Gray_Angel aka Shmupsik <shurikvz@mail.ru>
++ *
++ * 2004-2005 year
++ */
++/*
++ * 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 <stdarg.h>
++
++/****************************************************************************/
++/*
++ * function FILE *openfile(char *newfilename, const char *mode, bool silent)
++ *
++ * Input:
++ * newfilename - имя файла, который необходимо создать
++ * mode - режим открытия файла
++ *
++ * Output:
++ * указатель на файл
++ *
++ * Discription:
++ * функция осуществляет создание и открытие файла в указанном режиме
++ * и возвращает указатель на созданный файл
++ */
++static FILE *openfile(char *newfilename, const char *mode, bool silent) {
++ FILE *file;
++ static char *filename = NULL;
++
++ Context;
++
++ filename = (char *)nmalloc(sizeof(char) * (strlen(newfilename) + 1));
++
++ if (filename == NULL) {
++ putlog(LOG_MISC, "*", "logs2html: ERROR! Can't allocate enough space for filename.");
++ return NULL;
++ }
++
++ sprintf(filename, "%s", newfilename);
++ file = fopen(filename, mode);
++ if ((file == NULL) && (!silent)) {
++ putlog(LOG_MISC, "*", "logs2html: Warning! Can't open file \"%s\".", filename);
++ }
++
++ nfree(filename); filename = NULL;
++
++ return file;
++} /* openfile() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function void writefromexfile(FILE *dst_file, char *exfilename)
++ *
++ * Input:
++ *
++ *
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ *
++ *
++ */
++static void writefromexfile(FILE *dst_file, char *exfilename) {
++ FILE *addfile;
++ char buffer[512];
++ size_t n;
++
++ if (strlen(exfilename) > 0) {
++ if ((addfile = openfile(exfilename, "r", false)) != NULL) {
++ while(!feof(addfile)) {
++ n = fread(buffer, sizeof(char), sizeof buffer, addfile);
++ fwrite(buffer, sizeof(char), n, dst_file);
++ }
++ fclose(addfile);
++ }
++ }
++
++ return;
++} /* writefromexfile() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function void str_write(FILE *file, char *fmt, ... )
++ *
++ * Input:
++ * file - файл в который пишем данные
++ * fmt - строка для записи со спецификаторами формата
++ * ... - данные для записи в строку
++ *
++ * Output:
++ * ничего
++ *
++ * Discription:
++ * функция осуществляет запись переданной строки в указанный файл,
++ * производя соответствующее ее форматирование
++ */
++static void str_write(FILE *file, char *fstr, ... ) {
++ va_list ap;
++ int nchars;
++ int size = 256;
++ static char *buffer = NULL;
++
++ Context;
++ buffer = (char *)nmalloc(size);
++
++ va_start(ap, fstr);
++ while (true) {
++ nchars = egg_vsnprintf(buffer, size, fstr, ap);
++ if (nchars < size) break;
++ size *= 2;
++ buffer = (char *)nrealloc(buffer, size);
++ }
++ va_end(ap);
++ fwrite(buffer, sizeof(char), strlen(buffer), file);
++ nfree(buffer); buffer = NULL;
++
++ return;
++} /* str_write() */
++/****************************************************************************/
++
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/help/logs2html.help eggdrop1.6.19/src/mod/logs2html.mod/help/logs2html.help
+--- src/mod/logs2html.mod/help/logs2html.help 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/help/logs2html.help 2009-03-28 01:32:21.000000000 +0000
+@@ -0,0 +1,22 @@
++%{help=convertalllogs}%{+n}
++### %bconvertalllogs%b
++ Reconverts all your logs.
++
++See also: makemainpage
++%{help=makemainpage}%{+n}
++### %bmakemainpage%b
++ Redraws your mainpages.
++
++See also: convertalllogs
++%{help=logs2html module}%{+n}
++### %blogs2html module%b
++ This module convert all existing log files of your eggdrop for giving
++ channels to their html representation.
++
++ The following commands are provided by the logs2html module:
++%{+n}
++ %bconvertalllogs makemainpage%b
++%{help=all}%{+n}
++### %blogs2html module%b commands
++%{+n}
++ %bconvertalllogs makemainpage%b
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/language/logs2html.english.lang eggdrop1.6.19/src/mod/logs2html.mod/language/logs2html.english.lang
+--- src/mod/logs2html.mod/language/logs2html.english.lang 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/language/logs2html.english.lang 2009-03-28 01:32:53.000000000 +0000
+@@ -0,0 +1,38 @@
++# logs2html.english.lang
++# language messages for the logs2html module
++
++# Year
++0xe000,year
++
++# Back to mainpage link
++0xe001,Main page
++
++# Up link
++0xe002,up
++
++# Backward, forward link
++0xe003,back
++0xe004,next
++
++# Month names
++0xe005,January
++0xe006,February
++0xe007,March
++0xe008,April
++0xe009,May
++0xe010,June
++0xe011,July
++0xe012,August
++0xe013,September
++0xe014,October
++0xe015,November
++0xe016,December
++
++# Days of week names
++0xe017,Su
++0xe018,Mo
++0xe019,Tu
++0xe020,Wn
++0xe021,Th
++0xe022,Fr
++0xe023,St
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/language/logs2html.french.lang eggdrop1.6.19/src/mod/logs2html.mod/language/logs2html.french.lang
+--- src/mod/logs2html.mod/language/logs2html.french.lang 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/language/logs2html.french.lang 2009-03-28 01:32:53.000000000 +0000
+@@ -0,0 +1,38 @@
++# logs2html.french.lang
++# language messages for the logs2html module
++
++# Year
++0xe000,Annйe
++
++# Back to mainpage link
++0xe001,Page principale
++
++# Up link
++0xe002,haut
++
++# Backward, forward link
++0xe003,Prйcйdente
++0xe004,Suivante
++
++# Month names
++0xe005,Janvier
++0xe006,Fйvrier
++0xe007,Mars
++0xe008,Avril
++0xe009,Mai
++0xe010,Juin
++0xe011,Juillet
++0xe012,Aoыt
++0xe013,Septembre
++0xe014,Octobre
++0xe015,Novembre
++0xe016,Dйcembre
++
++# Days of week names
++0xe017,Di
++0xe018,Lu
++0xe019,Ma
++0xe020,Me
++0xe021,Je
++0xe022,Ve
++0xe023,Sa
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/language/logs2html.russian.lang eggdrop1.6.19/src/mod/logs2html.mod/language/logs2html.russian.lang
+--- src/mod/logs2html.mod/language/logs2html.russian.lang 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/language/logs2html.russian.lang 2009-03-28 01:32:21.000000000 +0000
+@@ -0,0 +1,38 @@
++# logs2html.ru.lang
++# language messages for the logs2html module
++
++# Year
++0xe000,год
++
++# Back to mainpage link
++0xe001,На главную страницу
++
++# Up link
++0xe002,наверх
++
++# Backward, forward link
++0xe003,предыдущая
++0xe004,следующая
++
++# Month names
++0xe005,Январь
++0xe006,Февраль
++0xe007,Март
++0xe008,Апрель
++0xe009,Май
++0xe010,Июнь
++0xe011,Июль
++0xe012,Август
++0xe013,Сентябрь
++0xe014,Октябрь
++0xe015,Ноябрь
++0xe016,Декабрь
++
++# Days of week names
++0xe017,Вс
++0xe018,Пн
++0xe019,Вт
++0xe020,Ср
++0xe021,Чт
++0xe022,Пт
++0xe023,Сб
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/language.h eggdrop1.6.19/src/mod/logs2html.mod/language.h
+--- src/mod/logs2html.mod/language.h 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/language.h 2009-03-28 01:32:21.000000000 +0000
+@@ -0,0 +1,51 @@
++/*
++ * language.h -- part of logs2html.mod
++ *
++ * Written by Fedotov Alexander aka Gray_Angel aka Shmupsik <shurikvz@mail.ru>
++ *
++ * 2004-2005 year
++ */
++/*
++ * 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.
++ */
++
++
++#define LOGS2HTML_YEAR get_language(0xe000)
++#define LOGS2HTML_MAINPAGE get_language(0xe001)
++#define LOGS2HTML_UP get_language(0xe002)
++#define LOGS2HTML_BACK get_language(0xe003)
++#define LOGS2HTML_NEXT get_language(0xe004)
++
++#define LOGS2HTML_JANUARY get_language(0xe005)
++#define LOGS2HTML_FEBRIARY get_language(0xe006)
++#define LOGS2HTML_MARCH get_language(0xe007)
++#define LOGS2HTML_APRIL get_language(0xe008)
++#define LOGS2HTML_MAY get_language(0xe009)
++#define LOGS2HTML_JUNE get_language(0xe010)
++#define LOGS2HTML_JULY get_language(0xe011)
++#define LOGS2HTML_AUGUST get_language(0xe012)
++#define LOGS2HTML_SEPTEMBER get_language(0xe013)
++#define LOGS2HTML_OCTOBER get_language(0xe014)
++#define LOGS2HTML_NOVEMBER get_language(0xe015)
++#define LOGS2HTML_DECEMBER get_language(0xe016)
++
++#define LOGS2HTML_SUNDAY get_language(0xe017)
++#define LOGS2HTML_MONDAY get_language(0xe018)
++#define LOGS2HTML_TUESDAY get_language(0xe019)
++#define LOGS2HTML_WEDNESDAY get_language(0xe020)
++#define LOGS2HTML_THURSDAY get_language(0xe021)
++#define LOGS2HTML_FRIDAY get_language(0xe022)
++#define LOGS2HTML_SATURDAY get_language(0xe023)
++
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/logs2html.c eggdrop1.6.19/src/mod/logs2html.mod/logs2html.c
+--- src/mod/logs2html.mod/logs2html.c 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/logs2html.c 2009-03-28 01:32:53.000000000 +0000
+@@ -0,0 +1,1572 @@
++/*
++ * logs2html.c -- part of logs2html.mod
++ *
++ * Written by Fedotov Alexander aka Gray_Angel aka Shmupsik <shurikvz@mail.ru>
++ *
++ * 2004-2005 year
++ */
++/*
++ * 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.
++ */
++
++
++#define MODULE_NAME "logs2html"
++#define MAKING_LOGS2HTML
++#include "src/mod/module.h"
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <time.h>
++#include <ctype.h>
++#include <sys/types.h>
++#include <math.h>
++#include "logs2html.h"
++#include "language.h"
++
++#undef global
++
++#define MODULE_MAJOR 2
++#define MODULE_MINOR 3
++#define MODULE_SUBMINOR 4
++
++static Function *global = NULL;
++
++#include "fileoperations.c"
++
++
++static int shtime;
++static int keep_all_logs;
++static char logfile_suffix[21];
++static char configfile[121];
++static int lines_per_page;
++
++static int days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
++
++static int month_cols_count = 3;
++static int month_rows_count = 4;
++
++static char mainpage_top_filename[257] = "\0";
++static char mainpage_bottom_filename[257] = "\0";
++static char logspage_top_filename[257] = "\0";
++static char logspage_bottom_filename[257] = "\0";
++static char chanlist_filename[257] = "\0";
++static char userstyle_filename[257] = "\0";
++static char encoding_string[31] = "\0";
++
++static logs2htmlchan *logs2htmlchanlist = NULL;
++
++/* for language file */
++static char month_names[12][21];
++static char days_names[7][21];
++
++static void logs2html_hook_5minutely(void);
++static void logs2html_hook_daily(void);
++static void logs2html_hook_pre_rehash(void);
++static void logs2html_hook_rehash(void);
++
++
++/* Calculate the memory we keep allocated.
++ */
++static int logs2html_expmem()
++{
++ logs2htmlchan *p;
++ int size = 0;
++
++ Context;
++ p = logs2htmlchanlist;
++ while (p != NULL) {
++ size++;
++ p = p->next;
++ }
++
++ size *= sizeof(struct logs2html_data);
++
++ return size;
++}
++
++
++/****************************************************************************/
++/*
++ * function int convertalllogs(struct userrec *u, int idx, char *par)
++ *
++ * Input:
++ *
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ *
++ */
++static int cmd_convertalllogs(struct userrec *u, int idx, char *par) {
++ int add_day;
++ logs2htmlchan *p;
++ int i, j, k;
++ struct tm tblock;
++ time_t t = time(NULL);
++ struct tm *st = localtime(&t);
++
++ tblock.tm_year = st->tm_year;
++ tblock.tm_isdst = st->tm_isdst;
++ tblock.tm_hour = 0;
++ tblock.tm_min = 0;
++ tblock.tm_sec = 1;
++ /* Other fields not necessary here
++ tblock.tm_mday = st->tm_mday;
++ tblock.tm_mon = st->tm_mon;
++ tblock.tm_wday = st->tm_wday;
++ tblock.tm_yday = st->tm_yday;
++ */
++
++ putlog(LOG_CMDS, "*", "#%s# start converting all log files.", dcc[idx].nick);
++ for (i = 0; i < 12; i++) {
++ add_day = ((i == 1) && isleap(tblock.tm_year)) ? 1 : 0;
++ for (j = 0; j < ((days_in_month[i]) + add_day); j++) {
++ tblock.tm_mon = i; tblock.tm_mday = j + 1;
++
++ tblock.tm_wday = (getdayofweek(tblock.tm_year + 1900, tblock.tm_mon + 1, tblock.tm_mday) + 1) % 7;
++ tblock.tm_yday = 0;
++ for (k = 0; k < tblock.tm_mon; k++) tblock.tm_yday += days_in_month[k];
++ tblock.tm_yday += tblock.tm_mday - 1;
++
++ p = logs2htmlchanlist;
++ while (p != NULL) {
++ convertfile(&tblock, p);
++ p = p->next;
++ }
++ }
++ }
++ putlog(LOG_CMDS, "*", "#%s# converting of all log files done.", dcc[idx].nick);
++
++ return 0;
++} /* convertalllogs() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function int cmd_makemainpage(struct userrec *u, int idx, char *par)
++ *
++ * Input:
++ *
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ *
++ */
++static int cmd_makemainpage(struct userrec *u, int idx, char *par) {
++ logs2htmlchan *p;
++
++ putlog(LOG_CMDS, "*", "#%s# starting making mainpages.", dcc[idx].nick);
++ p = logs2htmlchanlist;
++ while (p != NULL) {
++ dprintf(idx, "Making mainpage for channel '%s'...\n", p->channame);
++ makemainpage(p);
++ p = p->next;
++ }
++ putlog(LOG_CMDS, "*", "#%s# making of mainpages done.", dcc[idx].nick);
++
++ return 0;
++} /* convertalllogs() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function bool isvalidlink(char *link)
++ *
++ * Input:
++ * link - строка указывающая на ссылку
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ * Функция проверяет являются ли переданные в строке символы - символами
++ * допустимыми в ссылках
++ */
++static patternkind whatisit(char *pattern) {
++ char alpha_common[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789._-";
++ char alpha_http[] = "=?&/:%";
++ char *p;
++
++ if (strstr(pattern, "..") != NULL) {
++ return ITS_NOTHING;
++ }
++
++ p = strchr(pattern, '@');
++ if (p) {
++ /* it's can't be www link */
++
++ /* well, i can't imagine e-mail shorter than i@m.ru */
++ /* let's check it */
++ *p = '\0';
++ if (strlen(pattern) < 1) {
++ *p = '@';
++ return ITS_NOTHING;
++ }
++ while (*pattern) {
++ if (strchr(alpha_common, *pattern) == NULL) {
++ *p = '@';
++ return ITS_NOTHING;
++ }
++ pattern++;
++ }
++ *p = '@';
++ p++;
++ if (strlen(p) < 4) {
++ return ITS_NOTHING;
++ }
++ while (*p) {
++ if (strchr(alpha_common, *p) == NULL) return ITS_NOTHING;
++ p++;
++ }
++
++ return ITS_EMAIL;
++ } else {
++ if ((strncmp(pattern, "http://", 7) != 0) && (strncmp(pattern, "ftp://", 6) != 0)) {
++ if (strncmp(pattern, "www.", 4) != 0) {
++ return ITS_NOTHING;
++ } else {
++ while (*pattern) {
++ if ((strchr(alpha_common, *pattern) == NULL) && (strchr(alpha_http, *pattern) == NULL)) return ITS_NOTHING;
++ pattern++;
++ }
++
++ return ITS_TRUNKLINK;
++ }
++ }
++
++ while (*pattern) {
++ if ((strchr(alpha_common, *pattern) == NULL) && (strchr(alpha_http, *pattern) == NULL)) return ITS_NOTHING;
++ pattern++;
++ }
++
++ return ITS_LINK;
++ }
++
++ return ITS_NOTHING;
++} /* whatisit() */
++/****************************************************************************/
++
++
++/* A report on the module status.
++ *
++ * details is either 0 or 1:
++ * 0 - `.status'
++ * 1 - `.status all' or `.module woobie'
++ */
++static void logs2html_report(int idx, int details)
++{
++ if (details) {
++ int size = logs2html_expmem();
++
++ dprintf(idx, " Using %d byte%s of memory\n", size,
++ (size != 1) ? "s" : "");
++ }
++}
++
++static cmd_t mydcc[] = {
++ {"convertalllogs", "n", cmd_convertalllogs, NULL},
++ {"makemainpage", "n", cmd_makemainpage, NULL},
++ {NULL, NULL, NULL, NULL} /* Mark end. */
++};
++
++static tcl_strings my_tcl_strings[] = {
++ {"logfile-suffix", logfile_suffix, 20, STR_PROTECT},
++ {"config", configfile, 121, STR_PROTECT},
++ {"mainpage-top", mainpage_top_filename, 256, 0},
++ {"mainpage-bottom", mainpage_bottom_filename, 256, 0},
++ {"logspage-top", logspage_top_filename, 256, 0},
++ {"logspage-bottom", logspage_bottom_filename, 256, 0},
++ {"channels-list", chanlist_filename, 256, 0},
++ {"user-style", userstyle_filename, 256, 0},
++ {"insert-encoding-str", encoding_string, 30, 0},
++ {NULL, NULL, 0, 0} /* Mark end. */
++};
++
++static tcl_ints my_tcl_ints[] = {
++ {"col-count", &month_cols_count, 0},
++ {"lines-per-page", &lines_per_page, 0},
++ {"log-time", &shtime, 1},
++ {"keep-all-logs", &keep_all_logs, 1},
++ {NULL, NULL, 0} /* Mark end. */
++};
++
++static char *logs2html_close()
++{
++ logs2htmlchan *p, *q;
++
++ Context;
++ q = p = logs2htmlchanlist;
++ while (q != NULL) {
++ q = p->next;
++ nfree(p);
++ p = q;
++ }
++ logs2htmlchanlist = p = q = NULL;
++
++ del_lang_section(MODULE_NAME);
++ rem_help_reference(MODULE_NAME ".help");
++
++ del_hook(HOOK_DAILY, (Function)logs2html_hook_daily);
++ del_hook(HOOK_5MINUTELY, (Function)logs2html_hook_5minutely);
++ del_hook(HOOK_PRE_REHASH, (Function)logs2html_hook_pre_rehash);
++ del_hook(HOOK_REHASH, (Function)logs2html_hook_rehash);
++
++ rem_builtins(H_dcc, mydcc);
++ rem_tcl_ints(my_tcl_ints);
++ rem_tcl_strings(my_tcl_strings);
++
++ module_undepend(MODULE_NAME);
++ return NULL;
++}
++
++EXPORT_SCOPE char *logs2html_start();
++
++static Function logs2html_table[] = {
++ (Function) logs2html_start,
++ (Function) logs2html_close,
++ (Function) logs2html_expmem,
++ (Function) logs2html_report,
++};
++
++char *logs2html_start(Function *global_funcs)
++{
++ logs2htmlchan *ptr;
++
++ global = global_funcs;
++
++ Context;
++ /* Register the module. */
++ module_register(MODULE_NAME, logs2html_table, MODULE_MAJOR, MODULE_MINOR);
++
++ if (!module_depend(MODULE_NAME, "eggdrop", 106, 15)) {
++ module_undepend(MODULE_NAME);
++ return "This module requires Eggdrop 1.6.15 or later.";
++ }
++
++ add_tcl_ints(my_tcl_ints);
++
++ if (!keep_all_logs) {
++ rem_tcl_ints(my_tcl_ints);
++ module_undepend(MODULE_NAME);
++ return "This module requires \"keep-all-logs\" set to \"1\". Please check settings in your config file.";
++ }
++ logs2htmlchanlist = NULL; if (lines_per_page < 0) lines_per_page = 0;
++
++ add_tcl_strings(my_tcl_strings);
++
++ if (addchannels()) {
++ ptr = logs2htmlchanlist;
++ while (ptr != NULL) {
++ putlog(LOG_CMDS, "*", "logs2html: added channel %s, with path to logfiles \"%s\"...\n", ptr->channame, ptr->logfilename);
++ ptr = ptr->next;
++ }
++ } else {
++ rem_tcl_strings(my_tcl_strings);
++ rem_tcl_ints(my_tcl_ints);
++ module_undepend(MODULE_NAME);
++ return "No channels added. Please check settings in your eggdrop config file to be sure there is logfiles with mode set to \"p\".";
++ }
++
++ add_builtins(H_dcc, mydcc);
++
++ add_hook(HOOK_5MINUTELY, (Function)logs2html_hook_5minutely); //Для обновления лога за текущий день
++ add_hook(HOOK_DAILY, (Function)logs2html_hook_daily); //Последние 5 минут за прошлый день
++ add_hook(HOOK_PRE_REHASH, (Function)logs2html_hook_pre_rehash);
++ add_hook(HOOK_REHASH, (Function)logs2html_hook_rehash);
++
++ add_lang_section(MODULE_NAME);
++ add_help_reference(MODULE_NAME ".help");
++
++ month_names[0][0] = month_names[1][0] = month_names[2][0] = month_names[3][0] =
++ month_names[4][0] = month_names[5][0] = month_names[6][0] = month_names[7][0] =
++ month_names[8][0] = month_names[9][0] = month_names[10][0] = month_names[11][0] =
++ days_names[0][0] = days_names[1][0] = days_names[2][0] = days_names[3][0] =
++ days_names[4][0] = days_names[5][0] = days_names[6][0] = '\0';
++
++ strncpyz(month_names[0], LOGS2HTML_JANUARY, sizeof month_names[0]);
++ strncpyz(month_names[1], LOGS2HTML_FEBRIARY, sizeof month_names[1]);
++ strncpyz(month_names[2], LOGS2HTML_MARCH, sizeof month_names[2]);
++ strncpyz(month_names[3], LOGS2HTML_APRIL, sizeof month_names[3]);
++ strncpyz(month_names[4], LOGS2HTML_MAY, sizeof month_names[4]);
++ strncpyz(month_names[5], LOGS2HTML_JUNE, sizeof month_names[5]);
++ strncpyz(month_names[6], LOGS2HTML_JULY, sizeof month_names[6]);
++ strncpyz(month_names[7], LOGS2HTML_AUGUST, sizeof month_names[7]);
++ strncpyz(month_names[8], LOGS2HTML_SEPTEMBER, sizeof month_names[8]);
++ strncpyz(month_names[9], LOGS2HTML_OCTOBER, sizeof month_names[9]);
++ strncpyz(month_names[10], LOGS2HTML_NOVEMBER, sizeof month_names[10]);
++ strncpyz(month_names[11], LOGS2HTML_DECEMBER, sizeof month_names[11]);
++ strncpyz(days_names[0], LOGS2HTML_MONDAY, sizeof days_names[0]);
++ strncpyz(days_names[1], LOGS2HTML_TUESDAY, sizeof days_names[1]);
++ strncpyz(days_names[2], LOGS2HTML_WEDNESDAY, sizeof days_names[2]);
++ strncpyz(days_names[3], LOGS2HTML_THURSDAY, sizeof days_names[3]);
++ strncpyz(days_names[4], LOGS2HTML_FRIDAY, sizeof days_names[4]);
++ strncpyz(days_names[5], LOGS2HTML_SATURDAY, sizeof days_names[5]);
++ strncpyz(days_names[6], LOGS2HTML_SUNDAY, sizeof days_names[6]);
++
++ return NULL;
++}
++
++/*
++ * Code starts here
++ */
++
++/*
++ * getdayofweek()
++ * Input:
++ * year - год
++ * month - месяц
++ * day - день
++ *
++ * Output:
++ * 0 - Понедельник, 1 - Вторник, 2 - Среда и.т.д.
++ *
++ * Description:
++ * Функция вычисляет на какой день недели приходится переданная дата
++ */
++static int getdayofweek(int year, int month, int day)
++{
++ long int d1, d2, d3;
++
++ long int tdays = year * 12 + month - 3;
++ month = tdays % 12;
++ year = (tdays - month) / 12;
++
++ d1 = ((146097 * (year - (year % 100)) / 100) - ((146097 * (year - (year % 100)) / 100) % 4)) / 4;
++ d2 = ((1461 * (year % 100)) - ((1461 * (year % 100)) % 4)) / 4;
++ d3 = ((153 * month + 2) - ((153 * month + 2) % 5)) / 5 + day + 1721119;
++
++ return (d1 + d2 + d3) % 7;
++} /* getdayofweek() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function static int addchannels() {
++ *
++ * Input:
++ *
++ *
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ *
++ *
++ */
++static int addchannels() {
++ char buffer[512];
++ char *buf_ptr, *p;
++ logs2htmlchan *newchan, *ptr;
++ FILE *src_file;
++ int field_num;
++ int filelineread;
++ int channels_count = 0;
++
++
++ Context;
++ filelineread = 0;
++ if ((src_file = openfile(chanlist_filename, "r", true)) == NULL) return 0;
++ while (!feof(src_file)) {
++ buf_ptr = fgets(buffer, sizeof(buffer)-1, src_file);
++ if (buf_ptr == NULL) break;
++ filelineread++;
++
++ p = strrchr(buf_ptr, '\n');
++ if (p) *p = '\0';
++ p = strrchr(buf_ptr, '\r');
++ if (p) *p = '\0';
++ if (strlen(buf_ptr) == 0) continue;
++ while (isspace(*buf_ptr)) buf_ptr++;
++/* while (egg_isspace(*buf_ptr)) buf_ptr++; */
++ if (strncmp(buf_ptr, "addlogs2htmlchan", 16) == 0) p = buf_ptr += 16; else continue;
++ while (*p++) if (isspace(*p)) *p = ' ';
++/* while (*p++) if (egg_isspace(*p)) *p = ' '; */
++ if (!isspace(*buf_ptr)) continue;
++/* if (!egg_isspace(*buf_ptr)) continue; */
++ /*
++ At that point we have string of params of command "addlogs2htmlchan"
++ pointed by buf_ptr, with leading ' ';
++ */
++
++ newchan = (logs2htmlchan *)nmalloc(sizeof(logs2htmlchan) * 1);
++ if (newchan == NULL) {
++ nfree(newchan); newchan = NULL;
++ fclose(src_file);
++ putlog(LOG_MISC, "*", "Can't allocate enough space to add new channel!");
++ break;
++ }
++
++ newchan->next = NULL;
++ newchan->logfilename[0] = '\0';
++ newchan->channame[0] = '\0';
++ newchan->outputpath[0] = '\0';
++ newchan->mainpagename[0] = '\0';
++ newchan->mainpagetitle[0] = '\0';
++ newchan->logspagename[0] = '\0';
++ newchan->logspagetitle[0] = '\0';
++
++ field_num = 0;
++ while (*buf_ptr) {
++ while ((*buf_ptr) && (*buf_ptr == ' ')) buf_ptr++;
++ p = ++buf_ptr;
++ while ((*p) && (*p != '"')) p++;
++ *p = '\0';
++ switch (field_num) {
++ case 0: /* newchan->channame */
++ strncpyz(newchan->channame, buf_ptr, sizeof newchan->channame);
++ field_num = 1;
++ break;
++ case 1: /* newchan->outputpath */
++ strncpyz(newchan->outputpath, buf_ptr, sizeof newchan->outputpath);
++ field_num = 2;
++ break;
++ case 2: /* newchan->mainpagename */
++ strncpyz(newchan->mainpagename, buf_ptr, sizeof newchan->mainpagename);
++ field_num = 3;
++ break;
++ case 3: /* newchan->mainpagetitle */
++ strncpyz(newchan->mainpagetitle, buf_ptr, sizeof newchan->mainpagetitle);
++ field_num = 4;
++ break;
++ case 4: /* newchan->logspagename */
++ strncpyz(newchan->logspagename, buf_ptr, sizeof newchan->logspagename);
++ field_num = 5;
++ break;
++ case 5: /* newchan->logspagetitle */
++ strncpyz(newchan->logspagetitle, buf_ptr, sizeof newchan->logspagetitle);
++ field_num = 6;
++ break;
++ }
++ buf_ptr = ++p;
++ }
++
++
++ if (field_num != 6) {
++ nfree(newchan); newchan = NULL;
++ putlog(LOG_MISC, "*", "Error in file %s. String %d. Invalid expression \"addlogs2htmlchan\".", chanlist_filename, filelineread);
++ continue;
++ }
++
++ ptr = logs2htmlchanlist;
++ if (ptr == NULL) {
++ logs2htmlchanlist = newchan;
++ } else {
++ while (ptr->next != NULL) {
++ ptr = ptr->next;
++ }
++ ptr->next = newchan;
++ }
++ newchan = NULL;
++
++ }
++ fclose(src_file);
++
++ if ((src_file = openfile(configfile, "r", true)) == NULL) return 0;
++ while (!feof(src_file)) {
++ buf_ptr = fgets(buffer, sizeof(buffer)-1, src_file);
++ if (buf_ptr == NULL) break;
++
++ p = strrchr(buf_ptr, '\n');
++ if (p) *p = '\0';
++ p = strrchr(buf_ptr, '\r');
++ if (p) *p = '\0';
++ if (strlen(buf_ptr) == 0) continue;
++ while (isspace(*buf_ptr)) buf_ptr++;
++/* while (egg_isspace(*buf_ptr)) buf_ptr++; */
++ if (strncmp(buf_ptr, "logfile", 7) == 0) p = buf_ptr += 7; else continue;
++ while (*p++) if (isspace(*p)) *p = ' ';
++/* while (*p++) if (egg_isspace(*p)) *p = ' '; */
++ if (!isspace(*buf_ptr)) continue;
++/* if (!egg_isspace(*buf_ptr)) continue; */
++ /*
++ At that point we have string of params of command "logfile"
++ pointed by buf_ptr, with leading ' ';
++ */
++
++ p = newsplit(&buf_ptr);
++ if (logmodes(p) & LOG_PUBLIC) {
++ p = newsplit(&buf_ptr);
++ /*
++ At that point we have channel of command "logfile" pointed by p,
++ and the rest of the string (path to file), pointed by buf_ptr and enclosed with "
++ */
++ buf_ptr++; buf_ptr[strlen(buf_ptr)-1] = '\0';
++
++ ptr = logs2htmlchanlist;
++ while (ptr != NULL) {
++ if ((*p == '*') || (!rfc_casecmp(ptr->channame, p))) {
++ egg_snprintf(ptr->logfilename, sizeof ptr->logfilename, "%s", buf_ptr);
++ }
++ ptr = ptr->next;
++ }
++ }
++
++
++ }
++ fclose(src_file);
++
++
++ while (logs2htmlchanlist != NULL) {
++ if (strlen(logs2htmlchanlist->logfilename) == 0) {
++ ptr = logs2htmlchanlist;
++ logs2htmlchanlist = logs2htmlchanlist->next;
++ nfree(ptr);
++ } else {
++ ptr = logs2htmlchanlist;
++ while (ptr->next != NULL) {
++ if (strlen(ptr->next->logfilename) == 0) {
++ newchan = ptr->next;
++ ptr->next = ptr->next->next;
++ nfree(newchan);
++ } else {
++ ptr = ptr->next;
++ }
++ }
++ break;
++ }
++ }
++
++ ptr = logs2htmlchanlist;
++ while (ptr != NULL) {
++ channels_count++;
++ ptr = ptr->next;
++ }
++
++ ptr = newchan = NULL;
++
++ return channels_count;
++} /* addchannels() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function int convertfile(int year, int month, int day, bool convertifexists)
++ *
++ * Input:
++ *
++ *
++ *
++ * Output:
++ *
++ *
++ * Discription:
++ * переводит файлы из текстового вида в формат HTML
++ */
++static void convertfile(struct tm *t, logs2htmlchan *ch) {
++ char *buf_ptr, *p, *q, *r;
++ char buffer[LOGLINELEN], data[LOGLINELEN], ct[81], stamp[33];
++ char f_color[3], bg_color[3], text_style[6];
++ int mc_openteg_count = 0, pages_count = 0;
++ int i, j, k, lines_count, tsl;
++ char src_filename[257], dst_filename[257];
++ FILE *src_file, *dst_file;
++ bool bold_isopen, underline_isopen;
++ bool noneedtoclose, skipemail, linkfound;
++ char openspace[3] = " ( ";
++ char closespace[3] = " ),";
++ char *cuted_string = NULL;
++ int cuted_string_len, old_cuted_string_len, delta_cuted_string_len;
++ int r_offset, q_offset;
++ int *original_idx = NULL;
++
++ Context;
++ /* Let first write our default CSS file */
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%sdefault.css", ch->outputpath, SEP);
++ if ((dst_file = openfile(dst_filename, "wb", false)) != NULL) {
++ str_write(dst_file, "BODY {\n");
++ str_write(dst_file, "font-family: serif;\n");
++ str_write(dst_file, "font-style: normal\n");
++ str_write(dst_file, "font-variant: normal;\n");
++ str_write(dst_file, "font-weight: normal;\n");
++ str_write(dst_file, "font-stretch: normal;\n");
++ str_write(dst_file, "font-size: 12pt;\n");
++ str_write(dst_file, "text-align: left;\n");
++ str_write(dst_file, "color: rgb(0,0,0);\n");
++ str_write(dst_file, "background-color: transparent;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "BODY.mainpage {\n");
++ str_write(dst_file, "background-color: whitesmoke;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "BODY.logspage {\n");
++ str_write(dst_file, "background-color: lightyellow;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "TD {\n");
++ str_write(dst_file, "width: %d%%;\n", (int)floor(100.0/((double)month_cols_count * 8)));
++ str_write(dst_file, "background-color: lavender;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "TD.space {\n");
++ str_write(dst_file, "width: auto;\n");
++ str_write(dst_file, "background-color: whitesmoke;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "TD.dayname {\n");
++ str_write(dst_file, "width: auto;\n");
++ str_write(dst_file, "font-weight: bold;\n");
++ str_write(dst_file, "text-align: right;\n");
++ str_write(dst_file, "background-color: lightskyblue;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "TD.weekend {\n");
++ str_write(dst_file, "width: auto;\n");
++ str_write(dst_file, "font-weight: bold;\n");
++ str_write(dst_file, "text-align: right;\n");
++ str_write(dst_file, "color: red;\n");
++ str_write(dst_file, "background-color: lightskyblue;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "TH {\n");
++ str_write(dst_file, "font-weight: bold;\n");
++ str_write(dst_file, "text-align: center;\n");
++ str_write(dst_file, "background-color: lavender;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "SPAN.time {\n");
++ str_write(dst_file, "color: silver;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "SPAN.nick {\n");
++ str_write(dst_file, "color: mediumblue;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "SPAN.else {\n");
++ str_write(dst_file, "color: green;\n");
++ str_write(dst_file, "font-style: italic;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "SPAN.action {\n");
++ str_write(dst_file, "color: violet;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#footer {\n");
++ str_write(dst_file, " font-size: 10px;\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, " border-top-width: 1px;\n");
++ str_write(dst_file, " border-top-style: solid;\n");
++ str_write(dst_file, " border-color: #CCCCCC;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "h1 {\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#calendar {\n");
++ str_write(dst_file, " margin-right: auto;\n");
++ str_write(dst_file, " margin-left: auto;\n");
++ str_write(dst_file, " width: 90%;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#navtop {\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, " margin-top: 10px;\n");
++ str_write(dst_file, " margin-bottom: 10px;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#navbottom {\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, " margin-top: 10px;\n");
++ str_write(dst_file, " margin-bottom: 5px;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#totop {\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, " margin-top: 5px;\n");
++ str_write(dst_file, " margin-bottom: 10px;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "#log {\n");
++ str_write(dst_file, " margin-top: 10px;\n");
++ str_write(dst_file, " margin-bottom: 10px;\n");
++ str_write(dst_file, " padding-top: 10px;\n");
++ str_write(dst_file, " padding-bottom: 10px;\n");
++ str_write(dst_file, " border-width: thin;\n");
++ str_write(dst_file, " border-top-style: solid;\n");
++ str_write(dst_file, " border-bottom-style: solid;\n");
++ str_write(dst_file, " border-color: #CCCCCC;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, ".mainpage #title {\n");
++ str_write(dst_file, " font-size: 36px;\n");
++ str_write(dst_file, " text-align: center;\n");
++ str_write(dst_file, " margin-bottom: 20px;\n");
++ str_write(dst_file, " border-width: thin;\n");
++ str_write(dst_file, " border-color: #CCCCCC;\n");
++ str_write(dst_file, " border-bottom-style: solid;\n");
++ str_write(dst_file, "}\n");
++ str_write(dst_file, "SPAN.c0000, SPAN.c0100, SPAN.c0200, SPAN.c0300, SPAN.c0400, SPAN.c0500, SPAN.c0600, SPAN.c0700, SPAN.c0800, SPAN.c0900, SPAN.c1000, SPAN.c1100, SPAN.c1200, SPAN.c1300, SPAN.c1400, SPAN.c1500 {background-color: white;}\n");
++ str_write(dst_file, "SPAN.c0001, SPAN.c0101, SPAN.c0201, SPAN.c0301, SPAN.c0401, SPAN.c0501, SPAN.c0601, SPAN.c0701, SPAN.c0801, SPAN.c0901, SPAN.c1001, SPAN.c1101, SPAN.c1201, SPAN.c1301, SPAN.c1401, SPAN.c1501 {background-color: black;}\n");
++ str_write(dst_file, "SPAN.c0002, SPAN.c0102, SPAN.c0202, SPAN.c0302, SPAN.c0402, SPAN.c0502, SPAN.c0602, SPAN.c0702, SPAN.c0802, SPAN.c0902, SPAN.c1002, SPAN.c1102, SPAN.c1202, SPAN.c1302, SPAN.c1402, SPAN.c1502 {background-color: navy;}\n");
++ str_write(dst_file, "SPAN.c0003, SPAN.c0103, SPAN.c0203, SPAN.c0303, SPAN.c0403, SPAN.c0503, SPAN.c0603, SPAN.c0703, SPAN.c0803, SPAN.c0903, SPAN.c1003, SPAN.c1103, SPAN.c1203, SPAN.c1303, SPAN.c1403, SPAN.c1503 {background-color: green;}\n");
++ str_write(dst_file, "SPAN.c0004, SPAN.c0104, SPAN.c0204, SPAN.c0304, SPAN.c0404, SPAN.c0504, SPAN.c0604, SPAN.c0704, SPAN.c0804, SPAN.c0904, SPAN.c1004, SPAN.c1104, SPAN.c1204, SPAN.c1304, SPAN.c1404, SPAN.c1504 {background-color: red;}\n");
++ str_write(dst_file, "SPAN.c0005, SPAN.c0105, SPAN.c0205, SPAN.c0305, SPAN.c0405, SPAN.c0505, SPAN.c0605, SPAN.c0705, SPAN.c0805, SPAN.c0905, SPAN.c1005, SPAN.c1105, SPAN.c1205, SPAN.c1305, SPAN.c1405, SPAN.c1505 {background-color: maroon;}\n");
++ str_write(dst_file, "SPAN.c0006, SPAN.c0106, SPAN.c0206, SPAN.c0306, SPAN.c0406, SPAN.c0506, SPAN.c0606, SPAN.c0706, SPAN.c0806, SPAN.c0906, SPAN.c1006, SPAN.c1106, SPAN.c1206, SPAN.c1306, SPAN.c1406, SPAN.c1506 {background-color: purple;}\n");
++ str_write(dst_file, "SPAN.c0007, SPAN.c0107, SPAN.c0207, SPAN.c0307, SPAN.c0407, SPAN.c0507, SPAN.c0607, SPAN.c0707, SPAN.c0807, SPAN.c0907, SPAN.c1007, SPAN.c1107, SPAN.c1207, SPAN.c1307, SPAN.c1407, SPAN.c1507 {background-color: orange;}\n");
++ str_write(dst_file, "SPAN.c0008, SPAN.c0108, SPAN.c0208, SPAN.c0308, SPAN.c0408, SPAN.c0508, SPAN.c0608, SPAN.c0708, SPAN.c0808, SPAN.c0908, SPAN.c1008, SPAN.c1108, SPAN.c1208, SPAN.c1308, SPAN.c1408, SPAN.c1508 {background-color: yellow;}\n");
++ str_write(dst_file, "SPAN.c0009, SPAN.c0109, SPAN.c0209, SPAN.c0309, SPAN.c0409, SPAN.c0509, SPAN.c0609, SPAN.c0709, SPAN.c0809, SPAN.c0909, SPAN.c1009, SPAN.c1109, SPAN.c1209, SPAN.c1309, SPAN.c1409, SPAN.c1509 {background-color: lime;}\n");
++ str_write(dst_file, "SPAN.c0010, SPAN.c0110, SPAN.c0210, SPAN.c0310, SPAN.c0410, SPAN.c0510, SPAN.c0610, SPAN.c0710, SPAN.c0810, SPAN.c0910, SPAN.c1010, SPAN.c1110, SPAN.c1210, SPAN.c1310, SPAN.c1410, SPAN.c1510 {background-color: teal;}\n");
++ str_write(dst_file, "SPAN.c0011, SPAN.c0111, SPAN.c0211, SPAN.c0311, SPAN.c0411, SPAN.c0511, SPAN.c0611, SPAN.c0711, SPAN.c0811, SPAN.c0911, SPAN.c1011, SPAN.c1111, SPAN.c1211, SPAN.c1311, SPAN.c1411, SPAN.c1511 {background-color: cyan;}\n");
++ str_write(dst_file, "SPAN.c0012, SPAN.c0112, SPAN.c0212, SPAN.c0312, SPAN.c0412, SPAN.c0512, SPAN.c0612, SPAN.c0712, SPAN.c0812, SPAN.c0912, SPAN.c1012, SPAN.c1112, SPAN.c1212, SPAN.c1312, SPAN.c1412, SPAN.c1512 {background-color: blue;}\n");
++ str_write(dst_file, "SPAN.c0013, SPAN.c0113, SPAN.c0213, SPAN.c0313, SPAN.c0413, SPAN.c0513, SPAN.c0613, SPAN.c0713, SPAN.c0813, SPAN.c0913, SPAN.c1013, SPAN.c1113, SPAN.c1213, SPAN.c1313, SPAN.c1413, SPAN.c1513 {background-color: magenta;}\n");
++ str_write(dst_file, "SPAN.c0014, SPAN.c0114, SPAN.c0214, SPAN.c0314, SPAN.c0414, SPAN.c0514, SPAN.c0614, SPAN.c0714, SPAN.c0814, SPAN.c0914, SPAN.c1014, SPAN.c1114, SPAN.c1214, SPAN.c1314, SPAN.c1414, SPAN.c1514 {background-color: silver;}\n");
++ str_write(dst_file, "SPAN.c0015, SPAN.c0115, SPAN.c0215, SPAN.c0315, SPAN.c0415, SPAN.c0515, SPAN.c0615, SPAN.c0715, SPAN.c0815, SPAN.c0915, SPAN.c1015, SPAN.c1114, SPAN.c1215, SPAN.c1315, SPAN.c1415, SPAN.c1515 {background-color: gray;}\n");
++ str_write(dst_file, "SPAN.c0000, SPAN.c0001, SPAN.c0002, SPAN.c0003, SPAN.c0004, SPAN.c0005, SPAN.c0006, SPAN.c0007, SPAN.c0008, SPAN.c0009, SPAN.c0010, SPAN.c0011, SPAN.c0012, SPAN.c0013, SPAN.c0014, SPAN.c0015 {color: white;}\n");
++ str_write(dst_file, "SPAN.c0100, SPAN.c0101, SPAN.c0102, SPAN.c0103, SPAN.c0104, SPAN.c0105, SPAN.c0106, SPAN.c0107, SPAN.c0108, SPAN.c0109, SPAN.c0110, SPAN.c0111, SPAN.c0112, SPAN.c0113, SPAN.c0114, SPAN.c0115 {color: black;}\n");
++ str_write(dst_file, "SPAN.c0200, SPAN.c0201, SPAN.c0202, SPAN.c0203, SPAN.c0204, SPAN.c0205, SPAN.c0206, SPAN.c0207, SPAN.c0208, SPAN.c0209, SPAN.c0210, SPAN.c0211, SPAN.c0212, SPAN.c0213, SPAN.c0214, SPAN.c0215 {color: navy;}\n");
++ str_write(dst_file, "SPAN.c0300, SPAN.c0301, SPAN.c0302, SPAN.c0303, SPAN.c0304, SPAN.c0305, SPAN.c0306, SPAN.c0307, SPAN.c0308, SPAN.c0309, SPAN.c0310, SPAN.c0311, SPAN.c0312, SPAN.c0313, SPAN.c0314, SPAN.c0315 {color: green;}\n");
++ str_write(dst_file, "SPAN.c0400, SPAN.c0401, SPAN.c0402, SPAN.c0403, SPAN.c0404, SPAN.c0405, SPAN.c0406, SPAN.c0407, SPAN.c0408, SPAN.c0409, SPAN.c0410, SPAN.c0411, SPAN.c0412, SPAN.c0413, SPAN.c0414, SPAN.c0415 {color: red;}\n");
++ str_write(dst_file, "SPAN.c0500, SPAN.c0501, SPAN.c0502, SPAN.c0503, SPAN.c0504, SPAN.c0505, SPAN.c0506, SPAN.c0507, SPAN.c0508, SPAN.c0509, SPAN.c0510, SPAN.c0511, SPAN.c0512, SPAN.c0513, SPAN.c0514, SPAN.c0515 {color: maroon;}\n");
++ str_write(dst_file, "SPAN.c0600, SPAN.c0601, SPAN.c0602, SPAN.c0603, SPAN.c0604, SPAN.c0605, SPAN.c0606, SPAN.c0607, SPAN.c0608, SPAN.c0609, SPAN.c0610, SPAN.c0611, SPAN.c0612, SPAN.c0613, SPAN.c0614, SPAN.c0615 {color: purple;}\n");
++ str_write(dst_file, "SPAN.c0700, SPAN.c0701, SPAN.c0702, SPAN.c0703, SPAN.c0704, SPAN.c0705, SPAN.c0706, SPAN.c0707, SPAN.c0708, SPAN.c0709, SPAN.c0710, SPAN.c0711, SPAN.c0712, SPAN.c0713, SPAN.c0714, SPAN.c0715 {color: orange;}\n");
++ str_write(dst_file, "SPAN.c0800, SPAN.c0801, SPAN.c0802, SPAN.c0803, SPAN.c0804, SPAN.c0805, SPAN.c0806, SPAN.c0807, SPAN.c0808, SPAN.c0809, SPAN.c0810, SPAN.c0811, SPAN.c0812, SPAN.c0813, SPAN.c0814, SPAN.c0815 {color: yellow;}\n");
++ str_write(dst_file, "SPAN.c0900, SPAN.c0901, SPAN.c0902, SPAN.c0903, SPAN.c0904, SPAN.c0905, SPAN.c0906, SPAN.c0907, SPAN.c0908, SPAN.c0909, SPAN.c0910, SPAN.c0911, SPAN.c0912, SPAN.c0913, SPAN.c0914, SPAN.c0915 {color: lime;}\n");
++ str_write(dst_file, "SPAN.c1000, SPAN.c1001, SPAN.c1002, SPAN.c1003, SPAN.c1004, SPAN.c1005, SPAN.c1006, SPAN.c1007, SPAN.c1008, SPAN.c1009, SPAN.c1010, SPAN.c1011, SPAN.c1012, SPAN.c1013, SPAN.c1014, SPAN.c1015 {color: teal;}\n");
++ str_write(dst_file, "SPAN.c1100, SPAN.c1101, SPAN.c1102, SPAN.c1103, SPAN.c1104, SPAN.c1105, SPAN.c1106, SPAN.c1107, SPAN.c1108, SPAN.c1109, SPAN.c1110, SPAN.c1111, SPAN.c1112, SPAN.c1113, SPAN.c1114, SPAN.c1115 {color: cyan;}\n");
++ str_write(dst_file, "SPAN.c1200, SPAN.c1201, SPAN.c1202, SPAN.c1203, SPAN.c1204, SPAN.c1205, SPAN.c1206, SPAN.c1207, SPAN.c1208, SPAN.c1209, SPAN.c1210, SPAN.c1211, SPAN.c1212, SPAN.c1213, SPAN.c1214, SPAN.c1215 {color: blue;}\n");
++ str_write(dst_file, "SPAN.c1300, SPAN.c1301, SPAN.c1302, SPAN.c1303, SPAN.c1304, SPAN.c1305, SPAN.c1306, SPAN.c1307, SPAN.c1308, SPAN.c1309, SPAN.c1310, SPAN.c1311, SPAN.c1312, SPAN.c1313, SPAN.c1314, SPAN.c1315 {color: magenta;}\n");
++ str_write(dst_file, "SPAN.c1400, SPAN.c1401, SPAN.c1402, SPAN.c1403, SPAN.c1404, SPAN.c1405, SPAN.c1406, SPAN.c1407, SPAN.c1408, SPAN.c1409, SPAN.c1410, SPAN.c1411, SPAN.c1412, SPAN.c1413, SPAN.c1414, SPAN.c1415 {color: silver;}\n");
++ str_write(dst_file, "SPAN.c1500, SPAN.c1501, SPAN.c1502, SPAN.c1503, SPAN.c1504, SPAN.c1505, SPAN.c1506, SPAN.c1507, SPAN.c1508, SPAN.c1509, SPAN.c1510, SPAN.c1511, SPAN.c1512, SPAN.c1513, SPAN.c1514, SPAN.c1515 {color: gray;}\n");
++ str_write(dst_file, "SPAN.f00 {color: white;}\n");
++ str_write(dst_file, "SPAN.f01 {color: black;}\n");
++ str_write(dst_file, "SPAN.f02 {color: navy;}\n");
++ str_write(dst_file, "SPAN.f03 {color: green;}\n");
++ str_write(dst_file, "SPAN.f04 {color: red;}\n");
++ str_write(dst_file, "SPAN.f05 {color: maroon;}\n");
++ str_write(dst_file, "SPAN.f06 {color: purple;}\n");
++ str_write(dst_file, "SPAN.f07 {color: orange;}\n");
++ str_write(dst_file, "SPAN.f08 {color: yellow;}\n");
++ str_write(dst_file, "SPAN.f09 {color: lime;}\n");
++ str_write(dst_file, "SPAN.f10 {color: teal;}\n");
++ str_write(dst_file, "SPAN.f11 {color: cyan;}\n");
++ str_write(dst_file, "SPAN.f12 {color: blue;}\n");
++ str_write(dst_file, "SPAN.f13 {color: magenta;}\n");
++ str_write(dst_file, "SPAN.f14 {color: silver;}\n");
++ str_write(dst_file, "SPAN.f15 {color: gray;}\n");
++ str_write(dst_file, "SPAN.b00 {background-color: white;}\n");
++ str_write(dst_file, "SPAN.b01 {background-color: black;}\n");
++ str_write(dst_file, "SPAN.b02 {background-color: navy;}\n");
++ str_write(dst_file, "SPAN.b03 {background-color: green;}\n");
++ str_write(dst_file, "SPAN.b04 {background-color: red;}\n");
++ str_write(dst_file, "SPAN.b05 {background-color: maroon;}\n");
++ str_write(dst_file, "SPAN.b06 {background-color: purple;}\n");
++ str_write(dst_file, "SPAN.b07 {background-color: orange;}\n");
++ str_write(dst_file, "SPAN.b08 {background-color: yellow;}\n");
++ str_write(dst_file, "SPAN.b09 {background-color: lime;}\n");
++ str_write(dst_file, "SPAN.b10 {background-color: teal;}\n");
++ str_write(dst_file, "SPAN.b11 {background-color: cyan;}\n");
++ str_write(dst_file, "SPAN.b12 {background-color: blue;}\n");
++ str_write(dst_file, "SPAN.b13 {background-color: magenta;}\n");
++ str_write(dst_file, "SPAN.b14 {background-color: silver;}\n");
++ str_write(dst_file, "SPAN.b15 {background-color: gray;}\n");
++ fclose(dst_file);
++ }
++ /* Now write user CSS file */
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%suser.css", ch->outputpath, SEP);
++ if ((dst_file = openfile(dst_filename, "wb", false)) != NULL) {
++ writefromexfile(dst_file, userstyle_filename);
++ fclose(dst_file);
++ }
++
++ if (!logfile_suffix[0])
++ egg_strftime(ct, 12, ".%d%b%Y", t);
++ else
++ egg_strftime(ct, 80, logfile_suffix, t);
++ ct[80] = '\0';
++
++ egg_snprintf(src_filename, sizeof src_filename, "%s%s", ch->logfilename, ct);
++ if ((src_file = openfile(src_filename, "r", true)) == NULL) return;
++
++ while(!feof(src_file)) {
++ lines_count = lines_per_page; pages_count++;
++
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%s%s%d%02d%02d_pg%d.html", ch->outputpath, SEP, ch->logspagename, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, pages_count);
++ if ((dst_file = openfile(dst_filename, "wb", false)) == NULL) {
++ fclose(src_file);
++ putlog(LOG_MISC, "*", "logs2html: Error occured on converting %d page of file \"%s\"!", pages_count, dst_filename);
++ return;
++ }
++
++ str_write(dst_file, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
++ str_write(dst_file, "<html>\n");
++ str_write(dst_file, "<head>\n");
++ if (strlen(encoding_string) > 0) {
++ str_write(dst_file, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", encoding_string);
++ }
++ str_write(dst_file, "<meta name=\"title\" content=\"%s\">\n", ch->logspagetitle);
++ str_write(dst_file, "<meta name=\"Description\" content=\"%s\">\n", ch->logspagetitle);
++ str_write(dst_file, "<meta name=\"Generator\" content=\"logs2html module for Eggdrop v.%d.%d.%d\">\n", MODULE_MAJOR, MODULE_MINOR, MODULE_SUBMINOR);
++ str_write(dst_file, "<meta name=\"Author\" content=\"Fedotov Alexander aka Gray_Angel\">\n");
++ str_write(dst_file, "<meta name=\"Keywords\" content=\"logs, logging, channel, irc, bot, eggdrop, windrop, module, logs2html\">\n");
++ str_write(dst_file, "<meta name=\"robots\" content= \"index,all\">\n");
++ str_write(dst_file, "<link rel=stylesheet type=\"text/css\" href=\"default.css\">\n");
++ if (strlen(userstyle_filename) > 0) str_write(dst_file, "<link rel=stylesheet type=\"text/css\" href=\"user.css\">\n");
++ str_write(dst_file, "<title>%s. %d/%d/%d</title>\n", ch->logspagetitle, t->tm_mday, t->tm_mon + 1, t->tm_year + 1900);
++ str_write(dst_file, "</head>\n");
++ str_write(dst_file, "<body class=\"logspage\">\n");
++
++ writefromexfile(dst_file, logspage_top_filename);
++
++ str_write(dst_file, "<a name=\"top\"></a>\n");
++ str_write(dst_file, "<div id=\"navtop\"><a href=\"%s.html\">%s</a></div>\n", ch->mainpagename, LOGS2HTML_MAINPAGE);
++ str_write(dst_file, "<div id=\"log\">\n");
++
++ while ((lines_count > 0) || (lines_per_page == 0)) {
++ lines_count--;
++
++ buf_ptr = fgets(buffer, sizeof buffer, src_file);
++ if (buf_ptr == NULL) break;
++
++ p = strrchr(buf_ptr, '\n');
++ if (p) *p = '\0';
++ p = strrchr(buf_ptr, '\r');
++ if (p) *p = '\0';
++ if (!buf_ptr[0]) continue;
++
++ /* if timestamp exist cut time from string */
++ data[0] = '\0';
++ if (shtime) {
++ egg_strftime(stamp, sizeof(stamp) - 1, LOG_TS, t); /* Print dummy time */
++ tsl = strlen(stamp);
++ strncat(data, buf_ptr, tsl);
++ buf_ptr += (++tsl);
++ }
++ if (strncmp(buf_ptr, "--- ", 4) == 0) { /* we don't really need this string I think */
++ continue;
++ }
++ if (data && data[0]) {
++ str_write(dst_file, "<span class=\"time\">%s</span>", data);
++ }
++
++ data[0] = '\0'; noneedtoclose = false; skipemail = false;
++ if (strncmp(buf_ptr, "Action: ", 8) == 0) { /* command: /me */
++ buf_ptr += 7;
++ str_write(dst_file, "<span class=\"action\"> ***");
++ } else { /* nick */
++ p = strstr(buf_ptr, "> ");
++ if ((strncmp(buf_ptr, "<", 1) == 0) && (p != NULL)) {
++ buf_ptr++;
++ strncat(data, buf_ptr, p - buf_ptr);
++ str_write(dst_file, "<span class=\"nick\"> &lt;%s&gt;</span>", data);
++ buf_ptr += (p - buf_ptr + 1);
++ noneedtoclose = true;
++ } else {
++ str_write(dst_file, "<span class=\"else\"> ");
++ skipemail = true;
++ }
++ }
++
++ cuted_string_len = strlen(buf_ptr) + 2;
++ original_idx = (int *)nmalloc(sizeof(int) * (cuted_string_len + 1));
++ for (i = 0; i < cuted_string_len; i++) original_idx[i] = i - 1; original_idx[cuted_string_len] = -1;
++
++ cuted_string = (char *)nmalloc(cuted_string_len + 1);
++ egg_memset(cuted_string, 0, cuted_string_len + 1);
++ snprintf(cuted_string, cuted_string_len + 1, " %s ", buf_ptr);
++ q = r = cuted_string + 1;
++ /*
++ * Code copied from Eggdrop's src/dcc.c and then modified...
++ * Copyright (C) 1997 Robey Pointer
++ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Eggheads Development Team
++ */
++ while (*r) {
++ switch (*r) {
++ case 0xf:
++ case 3: /* mIRC colors? */
++ if (isdigit(r[1])) { /* Is the first char a number? */
++ r += 2; /* Skip over the ^C and the first digit */
++ if (isdigit(*r)) r++; /* Is this a double digit number? */
++ if (*r == ',') { /* Do we have a background color next? */
++ if (isdigit(r[1])) r += 2; /* Skip over the first background digit */
++ if (isdigit(*r)) r++; /* Is it a double digit? */
++ }
++ } else {
++ r++;
++ }
++ continue;
++ case 2: /* Bold text */
++ case 7:
++ case 0x16: /* Reverse video */
++ case 0x1f: /* Underlined text */
++ case 0x3c: /* < */
++ case 0x3e: /* > */
++ r++;
++ continue;
++ case 033:
++ r++;
++ if (*r == '[') {
++ r++;
++ while ((*r == ';') || isdigit(*r)) r++;
++ if (*r) r++; /* also kill the following char */
++ }
++ continue;
++ }
++ original_idx[q - cuted_string] = r - cuted_string - 1;
++ *q++ = *r++; /* Move on to the next char */
++ }
++ *q = '\0';
++ /*
++ * Ends here...
++ */
++
++ linkfound = false;
++ q = cuted_string;
++ while (*q) {
++ for (k = 0; k < MIN(sizeof openspace, sizeof closespace); k++) {
++ if (openspace[k] == *q) {
++ r = q + 1;
++ while (*r) {
++ if (closespace[k] == *r) {
++ *r = '\0';
++ p = q + 1;
++ switch (whatisit(p)) {
++ case ITS_NOTHING:
++ break;
++ case ITS_EMAIL:
++ if (!skipemail) { /* If class = "else", lets skip mail, because it ident@host */
++ egg_memset(data, 0, sizeof data);
++ sprintf(data, "<a href=\"mailto:%s\">", p);
++ linkfound = true;
++ }
++ break;
++ case ITS_LINK:
++ egg_memset(data, 0, sizeof data);
++ sprintf(data, "<a href=\"%s\">", p);
++ linkfound = true;
++ break;
++ case ITS_TRUNKLINK:
++ egg_memset(data, 0, sizeof data);
++ sprintf(data, "<a href=\"http://%s\">", p);
++ linkfound = true;
++ break;
++ }
++ *r = closespace[k];
++ if (linkfound) {
++ /* will after reallocation r & q pointers be aviable?
++ * i.e. will cuted_string begin with the same adress?
++ * to make them aviable let's count offset.
++ */
++ r_offset = r - cuted_string; q_offset = q - cuted_string;
++ old_cuted_string_len = strlen(cuted_string); delta_cuted_string_len = strlen(data) + strlen(T_LINKC);
++ cuted_string = (char *)nrealloc(cuted_string, old_cuted_string_len + delta_cuted_string_len + 1);
++ original_idx = (int *)nrealloc(original_idx, sizeof(int) * (old_cuted_string_len + delta_cuted_string_len + 1));
++ r = cuted_string + r_offset; q = cuted_string + q_offset;
++ for (i = old_cuted_string_len; i < (old_cuted_string_len + delta_cuted_string_len + 1); i++) {
++ original_idx[i] = -1; cuted_string[i] = '\0';
++ }
++ for (i = old_cuted_string_len - 1; i >= r_offset; i--) {
++ cuted_string[i + delta_cuted_string_len] = cuted_string[i];
++ original_idx[i + delta_cuted_string_len] = original_idx[i]; original_idx[i] = -1;
++ }
++ for (i = strlen(T_LINKC); i--; ) {
++ cuted_string[r_offset + delta_cuted_string_len - strlen(T_LINKC) + i] = T_LINKC[i];
++ }
++ for (i = r_offset - 1; i > q_offset; i--) {
++ cuted_string[i + delta_cuted_string_len - strlen(T_LINKC)] = cuted_string[i];
++ original_idx[i + delta_cuted_string_len - strlen(T_LINKC)] = original_idx[i]; original_idx[i] = -1;
++ }
++ for (i = 0; i < strlen(data); i++) {
++ cuted_string[q_offset + i + 1] = data[i];
++ original_idx[q_offset + i + 1] = -1;
++ }
++ }
++ if (linkfound) q = r - 1;
++ break;
++ }
++ r++;
++ }
++ }
++ if (linkfound) {
++ linkfound = false;
++ break;
++ }
++ }
++ q++;
++ }
++
++ cuted_string[strlen(cuted_string) - 1] = '\0';
++ egg_memset(data, 0, sizeof data);
++ bold_isopen = false; underline_isopen = false;
++ p = cuted_string + 1; /* Don't need first char cause it = ' ' */
++ q = buf_ptr;
++ while (*p) {
++ if ((original_idx[p - cuted_string] == -1) || (original_idx[p - cuted_string] == (q - buf_ptr))) {
++ if ((strlen(data) + 1) > (sizeof data - 1)) {
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ }
++ strncat(data, p, 1);
++ p++;
++ if (original_idx[p - cuted_string] != -1) q++;
++ } else {
++ /*
++ * Code copied from Eggdrop's src/dcc.c and then modified...
++ * Copyright (C) 1997 Robey Pointer
++ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Eggheads Development Team
++ */
++ switch (*q) {
++ case 2: /* Bold text */
++ if (bold_isopen) {
++ bold_isopen = false;
++ str_write(dst_file, "%s%s", data, T_BOLDC);
++ egg_memset(data, 0, sizeof data);
++ } else {
++ bold_isopen = true;
++ str_write(dst_file, "%s%s", data, T_BOLDO);
++ egg_memset(data, 0, sizeof data);
++ }
++ q++;
++ break;
++ case 3: /* mIRC colors? */
++ case 0xf: /* don't know, maybe broken client? but also mIRC colors */
++ egg_memset(f_color, 0, sizeof f_color); egg_memset(bg_color, 0, sizeof bg_color);
++ if (isdigit(q[1])) { /* Is the first char a number? */
++ f_color[0] = q[1];
++ if (isdigit(q[2])) {f_color[1] = q[2]; q++;}
++ q += 2;
++ if (*q == ',') {
++ if (isdigit(q[1])) { /* Is the first char a number? */
++ bg_color[0] = q[1];
++ if (isdigit(q[2])) {bg_color[1] = q[2]; q++;}
++ q += 2;
++ }
++ }
++ if (strlen(bg_color) > 0) {
++ /* If we have background color - let's close all previous "SPAN" */
++ for (mc_openteg_count++; --mc_openteg_count; ) {
++ if ((strlen(data) + strlen(T_SPANC)) > (sizeof data - 1)) {
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ }
++ strncat(data, T_SPANC, strlen(T_SPANC));
++ }
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ }
++
++ if ((strlen(f_color) > 0) && ((atoi(f_color) < 0) || (atoi(f_color) > 15))) {
++ egg_memset(f_color, 0, sizeof f_color);
++ }
++ if ((strlen(bg_color) > 0) && ((atoi(bg_color) < 0) || (atoi(bg_color) > 15))) {
++ egg_memset(bg_color, 0, sizeof bg_color);
++ }
++ if ((strlen(f_color) > 0) || (strlen(bg_color) > 0)) {
++ mc_openteg_count++;
++ text_style[0] = '\0';
++ if ((strlen(f_color) > 0) && (strlen(bg_color) > 0)) egg_snprintf(text_style, sizeof text_style, "c%02.2d%02.2d", atoi(f_color), atoi(bg_color));
++ if (strlen(bg_color) == 0) egg_snprintf(text_style, sizeof text_style, "f%02.2d", atoi(f_color));
++ if (strlen(f_color) == 0) egg_snprintf(text_style, sizeof text_style, "b%02.2d", atoi(bg_color));
++ str_write(dst_file, "%s<span class=\"%s\">", data, text_style);
++ egg_memset(data, 0, sizeof data);
++ }
++ } else {
++ /* It was "close-color" tag -> let's close all "SPAN" */
++ for (mc_openteg_count++; --mc_openteg_count; ) {
++ if ((strlen(data) + strlen(T_SPANC)) > (sizeof data - 1)) {
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ }
++ strncat(data, T_SPANC, strlen(T_SPANC));
++ }
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ q++;
++ }
++ break;
++ case 7: /* Bells */
++ q++;
++ break;
++ case 0x16: /* Reverse video */
++ q++;
++ break;
++ case 0x1f: /* Underlined text */
++ if (underline_isopen) {
++ underline_isopen = false;
++ str_write(dst_file, "%s%s", data, T_UNDERLINEC);
++ egg_memset(data, 0, sizeof data);
++ } else {
++ underline_isopen = true;
++ str_write(dst_file, "%s%s", data, T_UNDERLINEO);
++ egg_memset(data, 0, sizeof data);
++ }
++ q++;
++ break;
++ case 0x3c: /* < */
++ str_write(dst_file, "%s%s", data, T_LT);
++ egg_memset(data, 0, sizeof data);
++ q++;
++ break;
++ case 0x3e: /* > */
++ str_write(dst_file, "%s%s", data, T_GT);
++ egg_memset(data, 0, sizeof data);
++ q++;
++ break;
++ case 033:
++ q++;
++ if (*q == '[') {
++ q++;
++ while ((*q == ';') || isdigit(*q)) q++;
++ if (*q) q++; /* also kill the following char */
++ }
++ break;
++ default:
++ /* I think we should never get here, but if so... */
++ strncat(data, q, 1);
++ q++;
++ break;
++ }
++ /*
++ * Ends here...
++ */
++ }
++ }
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ if (bold_isopen) str_write(dst_file, "%s", T_BOLDC);
++ if (underline_isopen) str_write(dst_file, "%s", T_UNDERLINEC);
++ for (mc_openteg_count++; --mc_openteg_count; ) {
++ if ((strlen(data) + strlen(T_SPANC)) > (sizeof data - 1)) {
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++ }
++ strncat(data, T_SPANC, strlen(T_SPANC));
++ }
++ str_write(dst_file, "%s", data);
++ egg_memset(data, 0, sizeof data);
++
++ nfree(original_idx); original_idx = NULL;
++ nfree(cuted_string); cuted_string = NULL;
++
++ str_write(dst_file, "%s", data); data[0] = '\0';
++ str_write(dst_file, noneedtoclose ? "<br />\n":"</span><br />\n");
++ }
++ fclose(dst_file);
++ }
++ fclose(src_file);
++
++ for (i = 1; i <= pages_count; i++) {
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%s%s%d%02d%02d_pg%d.html", ch->outputpath, SEP, ch->logspagename, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, i);
++ if ((dst_file = openfile(dst_filename, "ab", false)) == NULL) {
++ putlog(LOG_MISC, "*", "logs2html: Error occured on converting %d page of file \"%s\"!", i, dst_filename);
++ return;
++ }
++ str_write(dst_file, "</div>\n");
++ if (pages_count > 1) {
++ str_write(dst_file, "<div id=\"navbottom\">");
++ if (i == 1) {
++ str_write(dst_file, LOGS2HTML_BACK);
++ } else {
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%d%02d%02d_pg%d.html", ch->logspagename, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, i-1);
++ str_write(dst_file, "<span>&larr;</span>&nbsp;<a href=\"%s\">%s</a>", dst_filename, LOGS2HTML_BACK);
++ }
++ str_write(dst_file, "&nbsp;");
++ if (i == pages_count) {
++ str_write(dst_file, LOGS2HTML_NEXT);
++ } else {
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%d%02d%02d_pg%d.html", ch->logspagename, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, i+1);
++ str_write(dst_file, "<a href=\"%s\">%s</a>&nbsp;<span>&rarr;</span>", dst_filename, LOGS2HTML_NEXT);
++ }
++ str_write(dst_file, "<br />");
++ for (j = 1; j <= pages_count; j++) {
++ egg_snprintf(dst_filename, sizeof dst_filename, "%s%d%02d%02d_pg%d.html", ch->logspagename, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, j);
++ if (j != i) {
++ str_write(dst_file, "<span> <a href=\"%s\">%d</a> </span>", dst_filename, j);
++ } else {
++ str_write(dst_file, "<b>%d</b>", j);
++ }
++ }
++ str_write(dst_file, "</div>\n");
++ }
++
++ str_write(dst_file, "<div id=\"totop\"><a href=\"#top\">%s</a></div>\n", LOGS2HTML_UP);
++
++ writefromexfile(dst_file, logspage_bottom_filename);
++
++ str_write(dst_file, "<div id=\"footer\">\nGenerated by logs2html module for eggdrop v.%d.%d.%d<br />\n", MODULE_MAJOR, MODULE_MINOR, MODULE_SUBMINOR);
++ str_write(dst_file, "Find latest version at <a href=\"http://sourceforge.net/projects/logs2html\">http://sourceforge.net/projects/logs2html</a> or <a href=\"http://shmupsik.osetia.org\">http://shmupsik.osetia.org</a>\n</div>\n");
++
++ str_write(dst_file, "</body>\n");
++ str_write(dst_file, "</html>");
++
++ fclose(dst_file);
++ }
++
++ return;
++} /* convertfile() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++/*
++ * function void makemainpage(logs2htmlchan *ch)
++ *
++ * Input:
++ * ничего
++ *
++ * Output:
++ * ничего
++ *
++ * Discription:
++ * Генерация основной страницы (календаря)
++ * + вызывается процедура для конвертирования логов в формат HTML
++ */
++static void makemainpage(logs2htmlchan *ch) {
++ int i, j, k, m, l;
++ int add_day;
++ FILE *file;
++ char filename[256];
++ bool endofyear;
++ struct tm tblock;
++ int delta_day = 0;
++ time_t t = time(NULL);
++ struct tm *st = localtime(&t);
++
++ tblock.tm_year = st->tm_year;
++ tblock.tm_isdst = st->tm_isdst;
++ tblock.tm_hour = 0;
++ tblock.tm_min = 0;
++ tblock.tm_sec = 1;
++ /* Other fields not necessary here
++ tblock.tm_mday = st->tm_mday;
++ tblock.tm_mon = st->tm_mon;
++ tblock.tm_wday = st->tm_wday;
++ tblock.tm_yday = st->tm_yday;
++ */
++
++ egg_snprintf(filename, sizeof filename, "%s%s%s.html", ch->outputpath, SEP, ch->mainpagename);
++ if ((file = openfile(filename, "wb", false)) == NULL) return;
++
++ str_write(file, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
++ str_write(file, "<html>\n");
++ str_write(file, "<head>\n");
++ if (strlen(encoding_string) > 0) {
++ str_write(file, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", encoding_string);
++ }
++ str_write(file, "<meta name=\"title\" content=\"%s\">\n", ch->mainpagetitle);
++ str_write(file, "<meta name=\"Description\" content=\"%s\">\n", ch->mainpagetitle);
++ str_write(file, "<meta name=\"Generator\" content=\"logs2html module for Eggdrop v.%d.%d.%d\">\n", MODULE_MAJOR, MODULE_MINOR, MODULE_SUBMINOR);
++ str_write(file, "<meta name=\"Author\" content=\"Fedotov Alexander aka Gray_Angel\">\n");
++ str_write(file, "<meta name=\"Keywords\" content=\"logs, logging, channel, irc, bot, eggdrop, windrop, module, logs2html\">\n");
++ str_write(file, "<meta name=\"robots\" content= \"index,all\">\n");
++ str_write(file, "<link rel=stylesheet type=\"text/css\" href=\"default.css\">\n");
++ if (strlen(userstyle_filename) > 0) str_write(file, "<link rel=stylesheet type=\"text/css\" href=\"user.css\">\n");
++ str_write(file, "<title>%s %d %s</title>\n", ch->mainpagetitle, tblock.tm_year + 1900, LOGS2HTML_YEAR);
++ str_write(file, "</head>\n");
++ str_write(file, "<body class=\"mainpage\">\n");
++
++ writefromexfile(file, mainpage_top_filename);
++
++ str_write(file, "<div id=\"title\">%s<br />%d %s</div>\n", ch->mainpagetitle, tblock.tm_year + 1900, LOGS2HTML_YEAR);
++ str_write(file, "<div id=\"calendar\">\n");
++
++
++ /* Вычисляем сколько рядов потребуется для размещения 12 месяцев при заданном числе столбцов */
++ month_rows_count = (int)ceil(12.0 / (double)month_cols_count);
++
++ str_write(file, "<table width=\"100%%\" cellspacing=\"2\" cellpadding=\"1\" border=\"0\">\n");
++
++ /* цикл по рядам месяцев */
++ for(i = 0; i < month_rows_count; i++) {
++
++ /* в каждом ряду: 1 строка (название месяца) + 7 строк (дни недели) */
++ for (j = 0; j < 8; j++) {
++ str_write(file, "<tr align=center>\n");
++
++ /* цикл по столбцам месяцев */
++ for (k = 0; k < month_cols_count; k++) {
++ tblock.tm_mon = i * month_cols_count + k;
++ endofyear = (tblock.tm_mon > 11 ) ? true : false;
++
++ if (j == 0) {
++ str_write(file, "<td class=\"space\"></td>");
++ str_write(file, "<th colspan=7>%s</th>\n", endofyear ? "&nbsp;": month_names[tblock.tm_mon]);
++ continue;
++ }
++
++ /* Если год високосный, то добавляем к февралю 1 день */
++ add_day = ((tblock.tm_mon == 1) && isleap(tblock.tm_year)) ? 1 : 0;
++
++ /* Для данного месяца данного года вычисляем на какой день недели приходится 1 число */
++ if (!endofyear) {
++ delta_day = getdayofweek(tblock.tm_year + 1900, tblock.tm_mon + 1, 1);
++ }
++
++ /* в каждом месяце: 2 столбца (название дней недели) + 6 столбцов (недели) */
++ for (m = 0; m < 7; m++) {
++ if (endofyear) {
++ str_write(file, "<td>&nbsp;</td>\n");
++ continue;
++ }
++ if (m == 0) {
++ str_write(file, "<td class=\"space\"></td>");
++ switch (j)
++ {
++ case 1:
++ case 2:
++ case 3:
++ case 4:
++ case 5:
++ case 6:
++ str_write(file, "<td class=\"dayname\">%s</td>\n", days_names[j-1]);
++ break;
++ case 7:
++ str_write(file, "<td class=\"weekend\">%s</td>\n", days_names[j-1]);
++ break;
++ default:
++ /* Uuups.. We should never get to this point.. and if it so, that mean's something wrong...:( */
++ str_write(file, "<td>&nbsp;</td>\n");
++ }
++ continue;
++ }
++ tblock.tm_mday = (m - 1) * 7 + j - delta_day;
++ if ((tblock.tm_mday >= 1) && (tblock.tm_mday <= (days_in_month[tblock.tm_mon] + add_day))) {
++ tblock.tm_wday = (getdayofweek(tblock.tm_year + 1900, tblock.tm_mon + 1, tblock.tm_mday) + 1) % 7;
++ tblock.tm_yday = 0;
++ for (l = 0; l < tblock.tm_mon; l++) tblock.tm_yday += days_in_month[l];
++ tblock.tm_yday += tblock.tm_mday - 1;
++
++ egg_snprintf(filename, sizeof filename, "%s%s%s%d%02d%02d_pg%d.html", ch->outputpath, SEP, ch->logspagename, tblock.tm_year + 1900, tblock.tm_mon + 1, tblock.tm_mday, 1);
++ if (!file_readable(filename)) convertfile(&tblock, ch);
++ if (file_readable(filename)) {
++ /* let write withount full path */
++ egg_snprintf(filename, sizeof filename, "%s%d%02d%02d_pg%d.html", ch->logspagename, tblock.tm_year + 1900, tblock.tm_mon + 1, tblock.tm_mday, 1);
++ str_write(file, "<td><a href=\"%s\">%d</A></td>\n", filename, tblock.tm_mday);
++ } else {
++ str_write(file, "<td>%d</td>\n", tblock.tm_mday);
++ }
++ } else {
++ str_write(file, "<td>&nbsp;</td>\n");
++ }
++ }
++ }
++ str_write(file, "</tr>\n");
++ }
++ str_write(file, "<tr><td class=\"space\" colspan=%d>&nbsp;</td></tr>\n", month_cols_count * 8);
++ }
++
++ str_write(file, "</table>\n");
++ str_write(file, "</div>\n");
++
++ writefromexfile(file, mainpage_bottom_filename);
++
++ str_write(file, "<div id=\"footer\">\nGenerated by logs2html module for eggdrop v.%d.%d.%d<br />\n", MODULE_MAJOR, MODULE_MINOR, MODULE_SUBMINOR);
++ str_write(file, "Find latest version at <a href=\"http://sourceforge.net/projects/logs2html\">http://sourceforge.net/projects/logs2html</a> or <a href=\"http://shmupsik.osetia.org\">http://shmupsik.osetia.org</a>\n</div>\n");
++
++ str_write(file, "</body>\n");
++ str_write(file, "</html>");
++
++ fclose(file);
++
++ return;
++} /* makemainpage() */
++/****************************************************************************/
++
++
++/****************************************************************************/
++static void logs2html_hook_5minutely(void)
++{
++ logs2htmlchan *p;
++ struct tm tblock;
++ time_t t = time(NULL);
++ struct tm *st = localtime(&t);
++
++ tblock.tm_year = st->tm_year;
++ tblock.tm_isdst = st->tm_isdst;
++ tblock.tm_mday = st->tm_mday;
++ tblock.tm_mon = st->tm_mon;
++ tblock.tm_wday = st->tm_wday;
++ tblock.tm_yday = st->tm_yday;
++ tblock.tm_hour = 0;
++ tblock.tm_min = 0;
++ tblock.tm_sec = 1;
++
++ p = logs2htmlchanlist;
++ while (p != NULL) {
++ convertfile(&tblock, p);
++ makemainpage(p);
++ p = p->next;
++ }
++
++ return;
++}
++/****************************************************************************/
++
++/****************************************************************************/
++static void logs2html_hook_daily(void)
++{
++ logs2htmlchan *p;
++ struct tm tblock;
++ time_t t = time(NULL);
++ struct tm *st = localtime(&t);
++
++ tblock.tm_year = st->tm_year;
++ tblock.tm_isdst = st->tm_isdst;
++ tblock.tm_mday = st->tm_mday;
++ tblock.tm_mon = st->tm_mon;
++ tblock.tm_wday = st->tm_wday;
++ tblock.tm_yday = st->tm_yday;
++ tblock.tm_hour = 0;
++ tblock.tm_min = 0;
++ tblock.tm_sec = 1;
++
++ if (!--tblock.tm_mday) {
++ if (!tblock.tm_mon) {
++ /* it's 1st January; lets go one day before */
++ tblock.tm_year--;
++ tblock.tm_mon = 11;
++ tblock.tm_mday = 31;
++ tblock.tm_yday = 364 + isleap(tblock.tm_year) ? 1 : 0;
++ } else {
++ tblock.tm_mon--;
++ tblock.tm_mday = days_in_month[tblock.tm_mon] + ((tblock.tm_mon == 1) && isleap(tblock.tm_year)) ? 1 : 0;
++ tblock.tm_yday--;
++ }
++ } else {
++ tblock.tm_yday--;
++ }
++ tblock.tm_wday = (tblock.tm_wday + 6) % 7;
++
++ p = logs2htmlchanlist;
++ while (p != NULL) {
++ convertfile(&tblock, p);
++ makemainpage(p);
++ p = p->next;
++ }
++
++ return;
++}
++/****************************************************************************/
++
++
++/****************************************************************************/
++static void logs2html_hook_pre_rehash(void)
++{
++ logs2htmlchan *p, *q;
++
++ q = p = logs2htmlchanlist;
++ while (q != NULL) {
++ q = p->next;
++ nfree(p);
++ p = q;
++ }
++ logs2htmlchanlist = p = q = NULL;
++
++ return;
++}
++/****************************************************************************/
++
++/****************************************************************************/
++static void logs2html_hook_rehash(void)
++{
++ if (lines_per_page < 0) lines_per_page = 0;
++
++ return;
++}
++/****************************************************************************/
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/logs2html.conf eggdrop1.6.19/src/mod/logs2html.mod/logs2html.conf
+--- src/mod/logs2html.mod/logs2html.conf 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/logs2html.conf 2009-03-28 01:43:58.000000000 +0000
+@@ -0,0 +1,38 @@
++######
++#####
++### General Settings
++#####
++######
++
++# number of rows the month'll put out
++set col-count 3
++
++# set how many lines there'll be on one page of converted logfile. If it
++# set to 0 then all converted log will dispalay as one page.
++set lines-per-page 200
++
++# Here specify file with "addlogs2html" expressions.
++set channels-list chan.list
++
++# Uncomment line if you want specify file with your color settings for
++# generated pages
++#set user-style user.css
++
++# This setting allows you to insert meta tag
++# <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=..."> in your
++# HTML files. You can comment next line, that will mean that this tag'll not
++# be insert in the resulting page.
++set insert-encoding-str "windows-1251"
++
++# Here you can specify path to files which content will be put to converted
++# logfile (or mainpage). Uncomment the line you need and put there
++# filename with path for example: set mainpage-top "top100.tpl"
++# Note: the content of specified file puts to the resulting file "as is",
++# without any transformation
++#set mainpage-top ""
++#set mainpage-bottom ""
++#set logspage-top ""
++#set logspage-bottom ""
++
++# now load the module
++loadmodule logs2html
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/logs2html.h eggdrop1.6.19/src/mod/logs2html.mod/logs2html.h
+--- src/mod/logs2html.mod/logs2html.h 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/logs2html.h 2009-03-28 01:46:28.000000000 +0000
+@@ -0,0 +1,76 @@
++/*
++ * logs2html.h -- part of logs2html.mod
++ *
++ * Written by Fedotov Alexander aka Gray_Angel aka Shmupsik <shurikvz@mail.ru>
++ *
++ * 2004-2005 year
++ */
++/*
++ * 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 "src/lang.h"
++
++#define SEP "/"
++
++#undef false
++#undef true
++typedef enum {false = 0, true} bool;
++
++#ifdef MIN
++# undef MIN
++#endif
++#define MIN(p,q) ((p < q) ? p : q)
++
++#ifndef isleap
++ /* Nonzero if YEAR is a leap year (every 4 years,
++ except every 100th isn't, and every 400th is). */
++#define isleap(year) \
++ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
++#endif
++
++#define T_LT "&lt;"
++#define T_GT "&gt;"
++#define T_BOLDO "<B>"
++#define T_BOLDC "</B>"
++#define T_UNDERLINEO "<U>"
++#define T_UNDERLINEC "</U>"
++#define T_SPANC "</SPAN>"
++#define T_LINKC "</A>"
++
++typedef struct logs2html_data {
++ struct logs2html_data *next;
++ char channame[81]; /* Имя канала для которого конвертировать логи */
++ char logfilename[128]; /* Имя (префикс) данного канала (вычисляется из выражения logfile в конфиге бота) */
++ char outputpath[128]; /* Куда выводить конвертированные логи */
++ char mainpagename[61]; /* Имя главной страницы */
++ char mainpagetitle[256]; /* Заголовок на главной странице */
++ char logspagename[61]; /* Имя (префикс) страницы переконвертированного логфайла */
++ char logspagetitle[256]; /* Заголовок страницы логфайла */
++} logs2htmlchan;
++
++typedef enum {ITS_NOTHING, ITS_EMAIL, ITS_LINK, ITS_TRUNKLINK} patternkind;
++
++static int cmd_convertalllogs(struct userrec *u, int idx, char *par);
++static int cmd_makemainpage(struct userrec *u, int idx, char *par);
++static int getdayofweek(int year, int month, int day);
++static FILE *openfile(char *newfilename, const char *mode, bool silent);
++static void str_write(FILE *file, char *fstr, ... );
++static void makemainpage(logs2htmlchan *ch);
++static void convertfile(struct tm *t, logs2htmlchan *ch);
++static void writefromexfile(FILE *dst_file, char *exfilename);
++static int addchannels(void);
++static patternkind whatisit(char *pattern);
++
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/logs2html.mod.desc eggdrop1.6.19/src/mod/logs2html.mod/logs2html.mod.desc
+--- src/mod/logs2html.mod/logs2html.mod.desc 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/logs2html.mod.desc 2009-03-28 01:46:37.000000000 +0000
+@@ -0,0 +1 @@
++This module convert all existing log files (and those, that will be created after module installation) of your eggdrop for givving channel to their html representation to be show in the web. and also the calendar page with links to that converted files.
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/modinfo eggdrop1.6.19/src/mod/logs2html.mod/modinfo
+--- src/mod/logs2html.mod/modinfo 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/modinfo 2009-03-28 01:32:21.000000000 +0000
+@@ -0,0 +1,4 @@
++DESC:This module convert all existing log files (and those, that will be
++DESC:created after module installation) of your eggdrop for givving channel
++DESC:to their html representation to be show in the web. and also the
++DESC:calendar page with links to that converted files.
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/readme.txt eggdrop1.6.19/src/mod/logs2html.mod/readme.txt
+--- src/mod/logs2html.mod/readme.txt 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/readme.txt 2009-03-28 01:44:20.000000000 +0000
+@@ -0,0 +1,85 @@
++logs2html.mod v.2.3.4 by Alexander Fedotov aka Gray_Angel aka Shmupsik #ircnet.ru
++e-mail: shurikvz@mail.ru
++
++This module convert all existing log files (and those, that will be created after module installation) of your eggdrop for giving channels to their html representation to be show in the web. and also the calendar page with links to that converted files.
++
++*******************************************************************************
++To install this module:
++ - copy the contents of "language" directory to your eggdrops "language" directory
++ - copy the contents of "help" directory to your eggdrops "help" directory
++ - copy *.dll (for windows) or *.so (for unix/linux) module to your eggdrops "modules" directory (only if you have download an arhive file with precompiled modules)
++ - copy logs2html.conf, chan.list files to your eggdrop directory
++ - if you decide to use your own style for pages copy user.css file to your eggdrop directory
++ - (Of course don't forget to edit logs2html.conf, chan.list and user.css files)
++ - put "source logs2html.conf" into your eggdrop config file and restart your bot
++
++Module has 2 commands, which you can use from dcc chat:
++ - convertalllogs - reconverts ALL your logs for current year (you'll need it for example if you decided to change style of your output logs even those which was created before your decision)
++ - makemainpage - redraws mainpages
++*******************************************************************************
++
++
++
++*******************************************************************************
++You can see the example of output on http://www.osetia.org/logs
++You can try to find latest version on http://sourceforge.net/projects/logs2html or http://shmupsik.osetia.org
++*******************************************************************************
++
++
++
++*******************************************************************************
++So, if you want to make a donation (for some strange reason I probably will never understand...) to me,
++you can do it using WebMoney (http://www.webmoney.ru).
++And here (http://webmoney.ru/wminouttrans1.shtml) a list of sites where you can exchange your money if you are not using WebMoney system.. :)
++
++My cash number: WMID:215902813411
++ U838552550724
++ E023251651728
++ R735356625383
++*******************************************************************************
++
++
++
++*******************************************************************************
++Version history:
++15.10.05 - version 2.3.4
++ - added setting in config file, which allow to change value of meta tag <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=..."> in generated HTML files.
++
++
++04.10.05 - version 2.3.3
++ - fixed bug with broken e-mail (strings with broken e-mails were truncated)
++
++
++ 24.09.05 - version 2.3.2
++ - added support for <B> and <U> tags
++ - fixed bug with [%H:%M:%S] timestamp (I hope.. :-))
++
++
++ 26.07.05 - version 2.3.1
++ - bug fixed
++
++
++ 24.07.05 - version 2.3.0
++ - page style discriptions moved to CSS file
++ - no need for tcl now
++ - small bugs fixed
++
++
++ 25.04.05 - version 2.1.0
++ - added support for http links and e-mail.
++
++
++ 27.02.05 - version 2.0
++ - converting logs for multiply channels
++ - possibility to change colors of HTML pages
++ - now you can aim number of lines on the one generated HTML page
++
++
++ 16.12.04 - version 1.0
++ - initial realise
++*******************************************************************************
++
++
++
++P.S. Sorry for my bad english
++
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/top100.tpl eggdrop1.6.19/src/mod/logs2html.mod/top100.tpl
+--- src/mod/logs2html.mod/top100.tpl 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/top100.tpl 2009-03-28 01:43:24.000000000 +0000
+@@ -0,0 +1,50 @@
++
++<p align="center">
++<!--Rating@Mail.ru COUNTER--><script language="JavaScript"><!--
++d=document;a='';a+=';r='+escape(d.referrer)
++js=10//--></script><script language="JavaScript1.1"><!--
++a+=';j='+navigator.javaEnabled()
++js=11//--></script><script language="JavaScript1.2"><!--
++s=screen;a+=';s='+s.width+'*'+s.height
++a+=';d='+(s.colorDepth?s.colorDepth:s.pixelDepth)
++js=12//--></script><script language="JavaScript1.3"><!--
++js=13//--></script><script language="JavaScript"><!--
++d.write('<img src="http://top.list.ru/counter'+'?id=606627;js='+js+a+';rand='+Math.random()+'" height=1 width=1>')
++if(js>11)d.write('<'+'!-- ')//--></script><noscript><img
++src="http://top.list.ru/counter?js=na;id=606627"
++height=1 width=1 alt=""></noscript><script language="JavaScript"><!--
++if(js>11)d.write('--'+'>')//--></script><!--/COUNTER-->
++<!-- SpyLOG f:0210 -->
++<script language="javascript"><!--
++Mu="u5131.64.spylog.com";Md=document;Mnv=navigator;Mp=1;
++Mn=(Mnv.appName.substring(0,2)=="Mi")?0:1;Mrn=Math.random();
++Mt=(new Date()).getTimezoneOffset();
++Mz="p="+Mp+"&rn="+Mrn+"&tl=0&ls=0&ln=0&t="+Mt;
++My="";
++My+="<img src='http://"+Mu+"/cnt?cid=513164&"+Mz+"&r="+escape(Md.referrer)+"&pg="+escape(window.location.href)+"'border=0 width=1 height=1 alt='SpyLOG'>";
++Md.write(My);//--></script><noscript>
++<img src="http://u5131.64.spylog.com/cnt?cid=513164&p=1" alt='SpyLOG' border='0' width=1
++height=1 >
++</noscript>
++<!-- SpyLOG -->
++<!--begin of Top100 logo-->
++<a href="http://top100.rambler.ru/top100/">
++<img src="http://top100-images.rambler.ru/top100/banner-88x31-rambler-blue.gif" alt="Rambler's Top100" width=88 height=31 border=0></a>
++<!--end of Top100 logo -->
++<script language="javascript"><!--
++Mrn=Math.random();Mz="";
++My="<a href='http://u5131.64.spylog.com/cnt?cid=513164&f=3&rn="+Mrn+"' target='_blank'><img src='http://u5131.64.spylog.com/cnt?cid=513164&";
++My+="p=1&f=4&rn="+Mrn+Mz+"' border=0 width=88 height=31 alt='SpyLOG'></a>";Md.write(My);
++//--></script><noscript>
++<a href="http://u5131.64.spylog.com/cnt?cid=513164&f=3&p=1" target="_blank">
++<img src="http://u5131.64.spylog.com/cnt?cid=513164&p=1&f=4" alt='SpyLOG' border='0' width=88 height=31 ></a>
++</noscript>
++<!--Rating@Mail.ru LOGO--><a target=_top
++href="http://top.mail.ru/jump?from=606627"><img src="http://top.list.ru/counter?id=606627;t=231;l=1"
++border=0 height=31 width=88
++alt="Рейтинг@Mail.ru"></a><!--/LOGO-->
++<!--begin of Rambler's Top100 code -->
++<a href="http://top100.rambler.ru/top100/">
++<img src="http://counter.rambler.ru/top100.cnt?503447" alt="" width=1 height=1 border=0></a>
++<!--end of Top100 code-->
++</p>
+diff -urpN eggdrop1.6.19-orig/src/mod/logs2html.mod/user.css eggdrop1.6.19/src/mod/logs2html.mod/user.css
+--- src/mod/logs2html.mod/user.css 1970-01-01 00:00:00.000000000 +0000
++++ src/mod/logs2html.mod/user.css 2009-03-28 01:32:53.000000000 +0000
+@@ -0,0 +1,121 @@
++BODY {
++font-family: serif;
++font-style: normal
++font-variant: normal;
++font-weight: normal;
++font-stretch: normal;
++font-size: 12pt;
++text-align: left;
++color: rgb(0,0,0);
++background-color: transparent;
++}
++BODY.mainpage {
++background-color: whitesmoke;
++}
++BODY.logspage {
++background-color: lightyellow;
++}
++TD {
++width: 4%;
++background-color: lavender;
++}
++TD.space {
++width: auto;
++background-color: whitesmoke;
++}
++TD.dayname {
++width: auto;
++font-weight: bold;
++text-align: right;
++background-color: lightskyblue;
++}
++TD.weekend {
++color: red;
++width: auto;
++font-weight: bold;
++text-align: right;
++width: auto;
++background-color: lightskyblue;
++}
++TH {
++font-weight: bold;
++text-align: center;
++background-color: lavender;
++}
++SPAN.time {
++color: silver;
++}
++SPAN.nick {
++color: mediumblue;
++}
++SPAN.else {
++color: green;
++font-style: italic;
++}
++SPAN.action {
++color: violet;
++}
++SPAN.c0000, SPAN.c0100, SPAN.c0200, SPAN.c0300, SPAN.c0400, SPAN.c0500, SPAN.c0600, SPAN.c0700, SPAN.c0800, SPAN.c0900, SPAN.c1000, SPAN.c1100, SPAN.c1200, SPAN.c1300, SPAN.c1400, SPAN.c1500 {background-color: white;}
++SPAN.c0001, SPAN.c0101, SPAN.c0201, SPAN.c0301, SPAN.c0401, SPAN.c0501, SPAN.c0601, SPAN.c0701, SPAN.c0801, SPAN.c0901, SPAN.c1001, SPAN.c1101, SPAN.c1201, SPAN.c1301, SPAN.c1401, SPAN.c1501 {background-color: black;}
++SPAN.c0002, SPAN.c0102, SPAN.c0202, SPAN.c0302, SPAN.c0402, SPAN.c0502, SPAN.c0602, SPAN.c0702, SPAN.c0802, SPAN.c0902, SPAN.c1002, SPAN.c1102, SPAN.c1202, SPAN.c1302, SPAN.c1402, SPAN.c1502 {background-color: navy;}
++SPAN.c0003, SPAN.c0103, SPAN.c0203, SPAN.c0303, SPAN.c0403, SPAN.c0503, SPAN.c0603, SPAN.c0703, SPAN.c0803, SPAN.c0903, SPAN.c1003, SPAN.c1103, SPAN.c1203, SPAN.c1303, SPAN.c1403, SPAN.c1503 {background-color: green;}
++SPAN.c0004, SPAN.c0104, SPAN.c0204, SPAN.c0304, SPAN.c0404, SPAN.c0504, SPAN.c0604, SPAN.c0704, SPAN.c0804, SPAN.c0904, SPAN.c1004, SPAN.c1104, SPAN.c1204, SPAN.c1304, SPAN.c1404, SPAN.c1504 {background-color: red;}
++SPAN.c0005, SPAN.c0105, SPAN.c0205, SPAN.c0305, SPAN.c0405, SPAN.c0505, SPAN.c0605, SPAN.c0705, SPAN.c0805, SPAN.c0905, SPAN.c1005, SPAN.c1105, SPAN.c1205, SPAN.c1305, SPAN.c1405, SPAN.c1505 {background-color: maroon;}
++SPAN.c0006, SPAN.c0106, SPAN.c0206, SPAN.c0306, SPAN.c0406, SPAN.c0506, SPAN.c0606, SPAN.c0706, SPAN.c0806, SPAN.c0906, SPAN.c1006, SPAN.c1106, SPAN.c1206, SPAN.c1306, SPAN.c1406, SPAN.c1506 {background-color: purple;}
++SPAN.c0007, SPAN.c0107, SPAN.c0207, SPAN.c0307, SPAN.c0407, SPAN.c0507, SPAN.c0607, SPAN.c0707, SPAN.c0807, SPAN.c0907, SPAN.c1007, SPAN.c1107, SPAN.c1207, SPAN.c1307, SPAN.c1407, SPAN.c1507 {background-color: orange;}
++SPAN.c0008, SPAN.c0108, SPAN.c0208, SPAN.c0308, SPAN.c0408, SPAN.c0508, SPAN.c0608, SPAN.c0708, SPAN.c0808, SPAN.c0908, SPAN.c1008, SPAN.c1108, SPAN.c1208, SPAN.c1308, SPAN.c1408, SPAN.c1508 {background-color: yellow;}
++SPAN.c0009, SPAN.c0109, SPAN.c0209, SPAN.c0309, SPAN.c0409, SPAN.c0509, SPAN.c0609, SPAN.c0709, SPAN.c0809, SPAN.c0909, SPAN.c1009, SPAN.c1109, SPAN.c1209, SPAN.c1309, SPAN.c1409, SPAN.c1509 {background-color: lime;}
++SPAN.c0010, SPAN.c0110, SPAN.c0210, SPAN.c0310, SPAN.c0410, SPAN.c0510, SPAN.c0610, SPAN.c0710, SPAN.c0810, SPAN.c0910, SPAN.c1010, SPAN.c1110, SPAN.c1210, SPAN.c1310, SPAN.c1410, SPAN.c1510 {background-color: teal;}
++SPAN.c0011, SPAN.c0111, SPAN.c0211, SPAN.c0311, SPAN.c0411, SPAN.c0511, SPAN.c0611, SPAN.c0711, SPAN.c0811, SPAN.c0911, SPAN.c1011, SPAN.c1111, SPAN.c1211, SPAN.c1311, SPAN.c1411, SPAN.c1511 {background-color: cyan;}
++SPAN.c0012, SPAN.c0112, SPAN.c0212, SPAN.c0312, SPAN.c0412, SPAN.c0512, SPAN.c0612, SPAN.c0712, SPAN.c0812, SPAN.c0912, SPAN.c1012, SPAN.c1112, SPAN.c1212, SPAN.c1312, SPAN.c1412, SPAN.c1512 {background-color: blue;}
++SPAN.c0013, SPAN.c0113, SPAN.c0213, SPAN.c0313, SPAN.c0413, SPAN.c0513, SPAN.c0613, SPAN.c0713, SPAN.c0813, SPAN.c0913, SPAN.c1013, SPAN.c1113, SPAN.c1213, SPAN.c1313, SPAN.c1413, SPAN.c1513 {background-color: magenta;}
++SPAN.c0014, SPAN.c0114, SPAN.c0214, SPAN.c0314, SPAN.c0414, SPAN.c0514, SPAN.c0614, SPAN.c0714, SPAN.c0814, SPAN.c0914, SPAN.c1014, SPAN.c1114, SPAN.c1214, SPAN.c1314, SPAN.c1414, SPAN.c1514 {background-color: silver;}
++SPAN.c0015, SPAN.c0115, SPAN.c0215, SPAN.c0315, SPAN.c0415, SPAN.c0515, SPAN.c0615, SPAN.c0715, SPAN.c0815, SPAN.c0915, SPAN.c1015, SPAN.c1114, SPAN.c1215, SPAN.c1315, SPAN.c1415, SPAN.c1515 {background-color: gray;}
++SPAN.c0000, SPAN.c0001, SPAN.c0002, SPAN.c0003, SPAN.c0004, SPAN.c0005, SPAN.c0006, SPAN.c0007, SPAN.c0008, SPAN.c0009, SPAN.c0010, SPAN.c0011, SPAN.c0012, SPAN.c0013, SPAN.c0014, SPAN.c0015 {color: white;}
++SPAN.c0100, SPAN.c0101, SPAN.c0102, SPAN.c0103, SPAN.c0104, SPAN.c0105, SPAN.c0106, SPAN.c0107, SPAN.c0108, SPAN.c0109, SPAN.c0110, SPAN.c0111, SPAN.c0112, SPAN.c0113, SPAN.c0114, SPAN.c0115 {color: black;}
++SPAN.c0200, SPAN.c0201, SPAN.c0202, SPAN.c0203, SPAN.c0204, SPAN.c0205, SPAN.c0206, SPAN.c0207, SPAN.c0208, SPAN.c0209, SPAN.c0210, SPAN.c0211, SPAN.c0212, SPAN.c0213, SPAN.c0214, SPAN.c0215 {color: navy;}
++SPAN.c0300, SPAN.c0301, SPAN.c0302, SPAN.c0303, SPAN.c0304, SPAN.c0305, SPAN.c0306, SPAN.c0307, SPAN.c0308, SPAN.c0309, SPAN.c0310, SPAN.c0311, SPAN.c0312, SPAN.c0313, SPAN.c0314, SPAN.c0315 {color: green;}
++SPAN.c0400, SPAN.c0401, SPAN.c0402, SPAN.c0403, SPAN.c0404, SPAN.c0405, SPAN.c0406, SPAN.c0407, SPAN.c0408, SPAN.c0409, SPAN.c0410, SPAN.c0411, SPAN.c0412, SPAN.c0413, SPAN.c0414, SPAN.c0415 {color: red;}
++SPAN.c0500, SPAN.c0501, SPAN.c0502, SPAN.c0503, SPAN.c0504, SPAN.c0505, SPAN.c0506, SPAN.c0507, SPAN.c0508, SPAN.c0509, SPAN.c0510, SPAN.c0511, SPAN.c0512, SPAN.c0513, SPAN.c0514, SPAN.c0515 {color: maroon;}
++SPAN.c0600, SPAN.c0601, SPAN.c0602, SPAN.c0603, SPAN.c0604, SPAN.c0605, SPAN.c0606, SPAN.c0607, SPAN.c0608, SPAN.c0609, SPAN.c0610, SPAN.c0611, SPAN.c0612, SPAN.c0613, SPAN.c0614, SPAN.c0615 {color: purple;}
++SPAN.c0700, SPAN.c0701, SPAN.c0702, SPAN.c0703, SPAN.c0704, SPAN.c0705, SPAN.c0706, SPAN.c0707, SPAN.c0708, SPAN.c0709, SPAN.c0710, SPAN.c0711, SPAN.c0712, SPAN.c0713, SPAN.c0714, SPAN.c0715 {color: orange;}
++SPAN.c0800, SPAN.c0801, SPAN.c0802, SPAN.c0803, SPAN.c0804, SPAN.c0805, SPAN.c0806, SPAN.c0807, SPAN.c0808, SPAN.c0809, SPAN.c0810, SPAN.c0811, SPAN.c0812, SPAN.c0813, SPAN.c0814, SPAN.c0815 {color: yellow;}
++SPAN.c0900, SPAN.c0901, SPAN.c0902, SPAN.c0903, SPAN.c0904, SPAN.c0905, SPAN.c0906, SPAN.c0907, SPAN.c0908, SPAN.c0909, SPAN.c0910, SPAN.c0911, SPAN.c0912, SPAN.c0913, SPAN.c0914, SPAN.c0915 {color: lime;}
++SPAN.c1000, SPAN.c1001, SPAN.c1002, SPAN.c1003, SPAN.c1004, SPAN.c1005, SPAN.c1006, SPAN.c1007, SPAN.c1008, SPAN.c1009, SPAN.c1010, SPAN.c1011, SPAN.c1012, SPAN.c1013, SPAN.c1014, SPAN.c1015 {color: teal;}
++SPAN.c1100, SPAN.c1101, SPAN.c1102, SPAN.c1103, SPAN.c1104, SPAN.c1105, SPAN.c1106, SPAN.c1107, SPAN.c1108, SPAN.c1109, SPAN.c1110, SPAN.c1111, SPAN.c1112, SPAN.c1113, SPAN.c1114, SPAN.c1115 {color: cyan;}
++SPAN.c1200, SPAN.c1201, SPAN.c1202, SPAN.c1203, SPAN.c1204, SPAN.c1205, SPAN.c1206, SPAN.c1207, SPAN.c1208, SPAN.c1209, SPAN.c1210, SPAN.c1211, SPAN.c1212, SPAN.c1213, SPAN.c1214, SPAN.c1215 {color: blue;}
++SPAN.c1300, SPAN.c1301, SPAN.c1302, SPAN.c1303, SPAN.c1304, SPAN.c1305, SPAN.c1306, SPAN.c1307, SPAN.c1308, SPAN.c1309, SPAN.c1310, SPAN.c1311, SPAN.c1312, SPAN.c1313, SPAN.c1314, SPAN.c1315 {color: magenta;}
++SPAN.c1400, SPAN.c1401, SPAN.c1402, SPAN.c1403, SPAN.c1404, SPAN.c1405, SPAN.c1406, SPAN.c1407, SPAN.c1408, SPAN.c1409, SPAN.c1410, SPAN.c1411, SPAN.c1412, SPAN.c1413, SPAN.c1414, SPAN.c1415 {color: silver;}
++SPAN.c1500, SPAN.c1501, SPAN.c1502, SPAN.c1503, SPAN.c1504, SPAN.c1505, SPAN.c1506, SPAN.c1507, SPAN.c1508, SPAN.c1509, SPAN.c1510, SPAN.c1511, SPAN.c1512, SPAN.c1513, SPAN.c1514, SPAN.c1515 {color: gray;}
++SPAN.f00 {color: white;}
++SPAN.f01 {color: black;}
++SPAN.f02 {color: navy;}
++SPAN.f03 {color: green;}
++SPAN.f04 {color: red;}
++SPAN.f05 {color: maroon;}
++SPAN.f06 {color: purple;}
++SPAN.f07 {color: orange;}
++SPAN.f08 {color: yellow;}
++SPAN.f09 {color: lime;}
++SPAN.f10 {color: teal;}
++SPAN.f11 {color: cyan;}
++SPAN.f12 {color: blue;}
++SPAN.f13 {color: magenta;}
++SPAN.f14 {color: silver;}
++SPAN.f15 {color: gray;}
++SPAN.b00 {background-color: white;}
++SPAN.b01 {background-color: black;}
++SPAN.b02 {background-color: navy;}
++SPAN.b03 {background-color: green;}
++SPAN.b04 {background-color: red;}
++SPAN.b05 {background-color: maroon;}
++SPAN.b06 {background-color: purple;}
++SPAN.b07 {background-color: orange;}
++SPAN.b08 {background-color: yellow;}
++SPAN.b09 {background-color: lime;}
++SPAN.b10 {background-color: teal;}
++SPAN.b11 {background-color: cyan;}
++SPAN.b12 {background-color: blue;}
++SPAN.b13 {background-color: magenta;}
++SPAN.b14 {background-color: silver;}
++SPAN.b15 {background-color: gray;}