#include "out_formats.h"
#include "out_xhtmlgen.h"
#include <time.h>
#include <math.h>
#define SET_MAX_IMAGES (4)
#define SET_MAX_HAPPY (6)
#define SET_MAX_PER_ROW (5)
int FUNCTION_NAME(FILE *outFile, t_stats *pStats, t_fisgconfig *pCfg)
{
char *hBarImages[SET_MAX_IMAGES] = { "blue-h.png", "green-h.png", "yellow-h.png", "red-h.png" };
char *vBarImages[SET_MAX_IMAGES] = { "blue-v.png", "green-v.png", "yellow-v.png", "red-v.png" };
t_ulint j, iRank;
int i, iHour;
t_float graphScale, happyScale, sadScale;
t_user_entry *tmpUser;
time_t tmpTime;
struct tm *tmpLocalTime;
char tmpTimeStr[SET_MAX_BUF];
t_str_index *tmpI;
t_str_node *tmpS;
/* Get time/date string */
time(&tmpTime);
tmpLocalTime = localtime(&tmpTime);
if (strftime(tmpTimeStr, sizeof(tmpTimeStr), pCfg->dateFormat, tmpLocalTime) == 0)
{
/* Unable to create string, make it empty */
tmpTimeStr[0] = 0;
}
/* Output stats as XHTML */
fprintf(outFile,
HTML_DOCTYPE
HTML_TAG
"<head>\n"
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n"
" <meta http-equiv=\"Cache-Control\" content=\"no-cache\" />\n"
);
fprintf(outFile,
" <link rel=\"stylesheet\" title=\"Default\" href=\"%s\" type=\"text/css\" />\n"
" <meta name=\"Author\" content=\"" FISG_NAME " v" FISG_VERSION " (" FISG_FULLNAME ")\" />\n"
" <title>" FISG_NAME " Statistics for %s%s%s</title>\n"
"</head>\n"
"<body>\n",
xhtml_cfg.cssPath,
pCfg->ircChannel,
(pCfg->ircNetwork) ? " @ " : "",
(pCfg->ircNetwork) ? pCfg->ircNetwork : ""
);
fprintf(outFile,
"<div class=\"ibodydiv\"" HTML_DIV_PARAMS ">\n"
"<div class=\"icontents\">\n"
" <div class=\"iinfo\">\n"
" <h1>%s%s%s</h1>\n"
" <p class=\"idate\">Statistics generated on <b>%s</b></p>\n"
/*
" <p class=\"ivisitors\">During this <b>%ld</b>-day reporting period, a total of <b>%ld</b> different nicks/users were represented on <b>%s</b>.</p>\n"
*/
" <p class=\"ivisitors\">A total of <b>%ld</b> different nicks/users were represented on <b>%s</b>.</p>\n"
"%s%s%s"
" </div>\n",
pCfg->ircChannel,
(pCfg->ircNetwork) ? " @ " : "",
(pCfg->ircNetwork) ? pCfg->ircNetwork : "",
tmpTimeStr,
/* pStats->nDays, */
pStats->usersList->n,
pCfg->ircChannel,
(pCfg->message) ? " <p class=\"imessage\">" : "",
(pCfg->message) ? pCfg->message : "",
(pCfg->message) ? "</p>\n" : ""
);
/*
* DAILY ACTIVITY
*/
if (pCfg->statActiveTimes)
{
if (pStats->activityPeak >= 0)
if (pStats->fActivityPerHour[pStats->activityPeak] > 0)
{
fprintf(outFile,
"<!-- ============================================= -->\n"
" <div class=\"ihourly\">\n"
" <h2>Most active times</h2>\n"
" <table" HTML_TABLE_PARAMS " class=\"ihourly\">\n"
" <tr>\n"
);
graphScale = (100 / pStats->fActivityPerHour[pStats->activityPeak]);
for (iHour = 0; iHour < SET_HOURS_DAY; iHour++)
{
fprintf(outFile,
" <th valign=\"bottom\">%1.1f%%<br />"
"<img src=\"%s/%s\" width=\"15\" height=\"%d\" alt=\"%1.1f%%\" /></th>\n",
pStats->fActivityPerHour[iHour],
xhtml_cfg.dataPath, vBarImages[iHour / SET_DAY_DIVISOR],
(int) (pStats->fActivityPerHour[iHour] * graphScale),
pStats->fActivityPerHour[iHour]);
}
fprintf(outFile,
" </tr>\n"
" <tr>\n"
);
for (iHour = 0; iHour < SET_HOURS_DAY; iHour++)
{
fprintf(outFile,
" <td class=\"%s\">%i</td>\n",
(iHour == pStats->activityPeak) ? "hirank" : "rank", iHour);
}
fprintf(outFile,
" </tr>\n"
" </table>\n"
"\n"
" <table" HTML_TABLE_PARAMS " class=\"ihourbars\">\n"
" <tr>\n"
);
for (iHour = 0; iHour < SET_HOURS_DAY; iHour += SET_DAY_DIVISOR)
{
fprintf(outFile,
" <td class=\"asmall\"><img src=\"%s/%s\" width=\"40\" height=\"15\" alt=\"%i-%i\" /> = %i-%i</td>\n",
xhtml_cfg.dataPath, hBarImages[iHour / SET_DAY_DIVISOR],
iHour, (iHour+SET_DAY_DIVISOR-1),
iHour, (iHour+SET_DAY_DIVISOR-1));
}
fprintf(outFile,
" </tr>\n"
" </table>\n"
" </div>\n"
);
}
} /* if (CFG_GEN_STAT_ACTIVE) */
/*
* TOP TALKERS
*/
if (pCfg->statTopUsers)
{
fprintf(outFile,
"<!-- ============================================= -->\n"
" <div class=\"itoptalkers\">\n"
" <h2>Most active users</h2>\n"
" <table" HTML_TABLE_PARAMS " class=\"itoptalkers\">\n"
" <tr>\n"
" <th width=\"2%%\" class=\"nrank\">#</th>\n"
);
fprintf(outFile,
"%s"
" <th width=\"10%%\" class=\"nhandle\">Nickname</th>\n"
" <th width=\"6%%\" class=\"npublics\">Lines</th>\n"
" <th width=\"15%%\" class=\"nactivity\">Activity</th>\n"
" <th width=\"5%%\" class=\"nwords\">Words</th>\n"
" <th width=\"2%%\" class=\"nwpp\">W/P</th>\n"
" <th width=\"2%%\" class=\"ncpw\">C/W</th>\n"
"%s"
"%s"
" </tr>\n",
(pCfg->showHappy) ? " <th width=\"2%%\" class=\"nhappiness\">?</th>\n" : "",
(pCfg->showComment) ? " <th width=\"50%%\" class=\"ncomment\">Comment</th>\n" : "",
(pCfg->showPicture) ? " <th width=\"5%%\" class=\"npicture\">Picture</th>\n" : ""
);
if (fabs(pStats->mostHappy->fHappiness) > 0)
happyScale = fabs(pStats->mostHappy->fHappiness);
else
happyScale = 1.0f;
if (fabs(pStats->mostSad->fHappiness) > 0)
sadScale = fabs(pStats->mostSad->fHappiness);
else
sadScale = 1.0f;
for (iRank = 0;
iRank < ((pStats->usersList->n >= pCfg->showTopUserMax) ?
pCfg->showTopUserMax : pStats->usersList->n);
iRank++)
{
/* Get user */
tmpUser = pStats->usersList->ppIndex[iRank];
if (!tmpUser) break;
/* Print one line */
fprintf(outFile,
" <tr>\n"
" <td class=\"nrank\">%ld</td>\n",
(iRank + 1)
);
if (pCfg->showHappy)
{
if (tmpUser->fHappiness > 0)
j = 3 + (int) ((tmpUser->fHappiness * 3.0f) / happyScale);
else
j = 3 + (int) ((tmpUser->fHappiness * 2.0f) / sadScale);
fprintf(outFile,
" <td class=\"nhappiness\"><img src=\"%s/happy%ld.gif\" alt=\"%ld\" /></td>\n",
xhtml_cfg.dataPath, j, j);
}
/* Print user handle with link URL, if specified */
if (tmpUser->linkURL && pCfg->showURL)
{
fprintf(outFile,
" <td class=\"nhandle\"><a href=\"");
xml_fprintf_urlencode(outFile, tmpUser->linkURL);
fprintf(outFile, "\">");
xml_fprintf_entitize(outFile, tmpUser->userHandle);
fprintf(outFile, "</a></td>\n");
} else {
fprintf(outFile,
" <td class=\"nhandle\">");
xml_fprintf_entitize(outFile, tmpUser->userHandle);
fprintf(outFile, "</td>\n");
}
fprintf(outFile,
" <td class=\"npublics\">%ld</td>\n"
" <td class=\"nactivity\">",
tmpUser->nPublics
);
for (iHour = 0; iHour < SET_HOURS_DAY; iHour += SET_DAY_DIVISOR)
{
graphScale = 0;
for (j = 0; j < SET_DAY_DIVISOR; j++)
graphScale += (tmpUser->fActivityPerHour[iHour + j] / 1.5f);
if (graphScale >= 1.0f)
{
fprintf(outFile,
"<img src=\"%s/%s\" width=\"%i\" height=\"15\" alt=\"\" />",
xhtml_cfg.dataPath, hBarImages[iHour / SET_DAY_DIVISOR],
(int) (graphScale));
}
}
fprintf(outFile,
"</td>\n"
" <td class=\"nwords\">%ld</td>\n"
" <td class=\"nwpp\">%1.2f</td>\n"
" <td class=\"ncpw\">%1.2f</td>\n",
tmpUser->nWords,
tmpUser->fWordsPerPublic,
tmpUser->fCharsPerWord
);
if (pCfg->showComment)
{
fprintf(outFile,
" <td class=\"ncomment\">");
if (tmpUser->sComment)
xml_fprintf_entitize(outFile, tmpUser->sComment);
fprintf(outFile, "</td>\n");
}
if (pCfg->showPicture)
{
fprintf(outFile,
" <td class=\"npicture\">");
if (tmpUser->picPath)
{
fprintf(outFile, "<img src=\"");
xml_fprintf_urlencode(outFile, xhtml_cfg.dataPath);
fprintf(outFile, "/");
xml_fprintf_urlencode(outFile, tmpUser->picPath);
fprintf(outFile, "\">");
}
fprintf(outFile, "</td>\n");
}
fprintf(outFile,
" </tr>\n");
}
fprintf(outFile,
" </table>\n"
"<!-- ============================================= -->\n"
);
/*
* ALMOST MADE IT...
*/
if (pCfg->statAlmostTop)
{
if (iRank < pStats->usersList->n)
{
fprintf(outFile,
" <h3>These didn't make it to the top:</h3>\n"
" <table" HTML_TABLE_PARAMS " class=\"ialmosttop\">\n"
);
j = (pStats->usersList->n >= (iRank + pCfg->showAlmostMax)) ? (iRank + pCfg->showAlmostMax) : pStats->usersList->n;
for (i = -1; iRank < j; iRank++)
{
/* Get user */
tmpUser = pStats->usersList->ppIndex[iRank];
if (!tmpUser) break;
if (i < 1)
{
if (i >= 0)
fprintf(outFile, " </tr>\n");
if ((j - iRank) >= SET_MAX_PER_ROW)
fprintf(outFile, " <tr>\n");
i = SET_MAX_PER_ROW;
}
/* Print user handle with link URL, if specified */
if (tmpUser->linkURL && pCfg->showURL)
{
fprintf(outFile,
" <td><a href=\"");
xml_fprintf_urlencode(outFile, tmpUser->linkURL);
fprintf(outFile, "\">");
xml_fprintf_entitize(outFile, tmpUser->userHandle);
fprintf(outFile, "</a> (%ld)</td>\n",
tmpUser->nPublics);
} else {
fprintf(outFile,
" <td>");
xml_fprintf_entitize(outFile, tmpUser->userHandle);
fprintf(outFile, " (%ld)</td>\n",
tmpUser->nPublics);
}
i--;
}
if (i >= 0)
fprintf(outFile, " </tr>\n");
fprintf(outFile,
" </table>\n"
);
/* Rest of nicks */
if (iRank < pStats->usersList->n)
{
fprintf(outFile,
" <h3>There were also <b>%ld</b> other nicks</h3>\n",
(pStats->usersList->n - iRank)
);
}
}
} /* if (CFG_GEN_STAT_ALMOST) */
fprintf(outFile,
" </div>\n"
"<!-- ============================================= -->\n"
);
} /* if (CFG_GEN_STAT_TOP) */
/*
* MOST REFERENCED URLS
*/
tmpI = pStats->urlIndex;
if (pCfg->statURLs && tmpI)
{
fprintf(outFile,
"<div class=\"iurls\">\n"
" <h2>Most referenced URLs</h2>\n"
" <table" HTML_TABLE_PARAMS " class=\"iurls\">\n"
" <tr>\n"
" <th width=\"2%%\" class=\"nrank\">#</th>\n"
" <th width=\"96%%\" class=\"nurl\">URL</th>\n"
" <th width=\"2%%\" class=\"nrefs\">References</th>\n"
" </tr>\n"
);
for (iRank = 0; iRank < ((tmpI->n >= pCfg->showURLsMax) ? pCfg->showURLsMax : tmpI->n); iRank++)
{
tmpS = tmpI->ppIndex[iRank];
fprintf(outFile,
" <tr><td class=\"nrank\">%ld</td>"
"<td class=\"nurl\"><a href=\"http://",
(iRank + 1));
xml_fprintf_urlencode(outFile, tmpS->pcStr);
fprintf(outFile, "\">http://");
xml_fprintf_entitize(outFile, tmpS->pcStr);
fprintf(outFile,
"</a></td><td class=\"nrefs\">%ld</td></tr>\n",
tmpS->nUsed);
}
fprintf(outFile,
" </table>\n"
"</div>\n"
"<!-- ============================================= -->\n"
);
}
/*
* BIG NUMBERS
*/
if (pCfg->statBigNumbers)
{
fprintf(outFile,
"<div class=\"ibignumbers\">\n"
" <h2>Big Numbers</h2>\n");
if (pStats->mostStupid && (pStats->mostStupid->nQuestions > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" Is <b>%s</b> stupid or just asking too many questions? <b>%1.1f%%</b> of his lines contained a question!\n"
" </p>\n",
pStats->mostStupid->userHandle,
((t_float) pStats->mostStupid->nQuestions / (t_float) pStats->mostStupid->nPublics) * 100.0f);
}
if (pStats->mostLoud && (pStats->mostLoud->nYelling > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" The loudest one was <b>%s</b>, who yelled <b>%1.1f%%</b> of the time."
" </p>\n",
pStats->mostLoud->userHandle,
((t_float) pStats->mostLoud->nYelling / (t_float) pStats->mostLoud->nPublics) * 100.0f);
}
if (pStats->mostURLs && (pStats->mostURLs->nURLs > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" Total of <b>%ld</b> URLs were pasted by <b>%s</b>!!\n"
" </p>\n",
pStats->mostURLs->nURLs, pStats->mostURLs->userHandle);
}
if (pStats->mostJoins && (pStats->mostJoins->nJoins > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" <b>%s</b> didn't know whether to stay. He/she joined the channel <b>%ld</b> times!\n"
" </p>\n",
pStats->mostJoins->userHandle, pStats->mostJoins->nJoins);
}
if (pStats->mostKicks && (pStats->mostKicks->nKicks > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" <b>%s</b> kicked the ass most, <b>%ld</b> times to be exact!\n"
" </p>\n",
pStats->mostKicks->userHandle, pStats->mostKicks->nKicks);
}
if (pStats->mostKicked && (pStats->mostKicked->nGotKicked > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" Obviously someone does not like <b>%s</b>, he/she was kicked <b>%ld</b> times!\n"
" </p>\n",
pStats->mostKicked->userHandle, pStats->mostKicked->nGotKicked);
}
if (pStats->mostCaps && (pStats->mostCaps->fCapsPercent > 0.1f))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" <b>%s</b> is a clear caps-abuser, <b>%1.1f%%</b> of time he/she wrote in CAPS."
" </p>\n",
pStats->mostCaps->userHandle, pStats->mostCaps->fCapsPercent);
}
if (pStats->mostHappy)
{
fprintf(outFile,
" <p class=\"isection\">\n"
" <b>%s</b> is either using drugs or is otherwise very <b>happy</b> person <b>;D</b>"
" </p>\n",
pStats->mostHappy->userHandle);
}
if (pStats->mostSad)
{
fprintf(outFile,
" <p class=\"isection\">\n"
" On the other hand <b>%s</b> seems to be quite <b>sad</b> <b>:(</b>"
" </p>\n",
pStats->mostSad->userHandle);
}
if (pStats->mostTopics && (pStats->mostTopics->nTopics > 0))
{
fprintf(outFile,
" <p class=\"isection\">\n"
" <b>%s</b> changed the topic <b>%ld</b> times!\n"
" </p>\n",
pStats->mostTopics->userHandle, pStats->mostTopics->nTopics);
}
fprintf(outFile,
"</div>\n"
"<!-- ============================================= -->\n"
);
}
/*
* LATEST TOPICS
*/
tmpI = pStats->topicIndex;
if (pCfg->statTopics && tmpI)
{
fprintf(outFile,
"<div class=\"itopics\">\n"
" <h2>Latest topics</h2>\n"
" <table" HTML_TABLE_PARAMS " class=\"itopics\">\n"
" <tr>\n"
" <th width=\"90%%\" class=\"ntopic\">Topic</th>\n"
" <th width=\"10%%\" class=\"nsetby\">Set by</th>\n"
" </tr>\n"
);
for (iRank = 0; iRank < ((tmpI->n >= pCfg->showTopicsMax) ? pCfg->showTopicsMax : tmpI->n); iRank++)
{
tmpS = tmpI->ppIndex[iRank];
fprintf(outFile, " <tr><td class=\"ntopic\">");
xml_fprintf_entitize(outFile, tmpS->pcStr);
fprintf(outFile, "</td><td class=\"nsetby\">");
if (tmpS->pData)
{
xml_fprintf_entitize(outFile,
((t_user_entry *) tmpS->pData)->userHandle);
}
fprintf(outFile, "</td></tr>\n");
}
fprintf(outFile,
" </table>\n"
"</div>\n"
"<!-- ============================================= -->\n"
);
}
/*
* INFO footer
*/
fprintf(outFile,
" <div class=\"irestinfo\">\n"
" <p class=\"ilines\">Totals analyzed: <b>%ld</b> lines in <b>%ld</b> logfiles"
" summing to appr. <b>%1.2f</b> MB.</p>\n"
" <p class=\"iauthor\">Statistics generated by "
"<a href=\"http://www.tnsp.org/fisg.php\">" FISG_NAME
" (" FISG_FULLNAME ") v" FISG_VERSION "</a> " FISG_COPYRIGHT "</p>\n"
" <p class=\"itime\">Stats generated in <b>%ld hours, %ld minutes and %ld seconds</b>.</p>\n"
" </div>\n",
pStats->nLines, pStats->nLogFiles, ((t_float) pStats->nChars) / (1024.0f*1024.0f),
(pStats->nTimeElapsed / (60*60)),
(pStats->nTimeElapsed % (60*60)) / 60,
(pStats->nTimeElapsed % (60*60)) % 60
);
/* Output HTML footer */
fprintf(outFile,
"<!-- ============================================= -->\n"
"</div>\n"
"</div>\n"
"</body>\n"
"</html>\n");
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1