/*
* 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 Library 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.
squidview 0.8x
A program to nicely browse your squid log
(c) 2001 - 2013 Graeme Sheppard
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <curses.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string>
using namespace std;
#define nInputLen 80
#define nReadBuffer 2048
// fields/columns of squid log lines
int iTimeCol = -1;
int iCacheHitCol = -1;
int iSizeCol = -1;
int iTargetCol = -1;
int iUserCol = -1;
int iIPCol = -1;
int iUserNameLen = 8; // maximum displayed width of a login name
#define nSizeCols 11 // width given to display size of requests
typedef off_t tFilePos; // positions in log file are of this type
typedef uint64_t tByteTotal; // for summing bytes transferred
typedef uint32_t tIPnum; // IP aliases only 32 bit at this stage
const time_t nSecsInDay = 60 * 60 * 24;
const char cEOL = 10; // End Of Line character
const char cCR = 13;
const char cSeperator = 10;
string sHomeDir;
const char szSquidHome[] = ".squidview";
string sPathToFiles;
const string sLogLocations[] = {"/var/log/squid/access.log",
"/usr/local/squid/var/logs/access.log", ""};
// disribution builders: put your log location first in the list
// last entry must be ""
const char szLog1[] = "log1";
const char szLog2[] = "log2";
const char szLog3[] = "log3";
const char szLabel1[] = "Pri";
const char szLabel2[] = "Sec";
const char szLabel3[] = "Tri";
const char* pszCurrentLog;
const char* pszCurrentName;
const char szWordFile[] = "words"; // search words
const char szUsersFile[] = "users"; // list of real names
const char szAliasesFile[] = "aliases"; // map IPs to user names
const char szHowToFile[] = "HOWTO"; // link name
string sLogFile1, sLogFile2, sLogFile3;
string sWordFile, sUsersFile, sAliasesFile, sSetFileName, sHowToLink;
int fReadingFile = -1;
char const *pszReadingFile = 0;
string sViewer = "less";
string sCurrentReport = "";
string sCurrentEmail = "";
const string sReportExt = ".txt";
char cDiskBuffer [nReadBuffer +8]; // buffer for log read
char szEmpty = '\0'; // null string...
char* pcEmpty = &szEmpty; // ...pointed to by this
char* pcReqBuff = pcEmpty; // normally the start of the request
// or above if the read op fails
string sWords;
string sStatusMessage = "";
int iSizeHitGrade = 0;
int iSizeHitBytes = 0;
string sSizeHits = "50000 250000 1000000 10000000";
WINDOW* wTemp = 0; // dummy window
tFilePos iPagePos, // point in log file of top of current screen
iLastPage, // " " " " " of last screen
iLogFileSize,
iLinePos, // where the current highlighted line is
iLastLinePos; // the last line in log file
int iMainLines, // no. of lines in main window
iLinesDown, // which line the highlight bar is at
iMaxLinesDown, // in the case of very small log files
iMonitorMode = 1, // like the Unix command tail
iCurrentLog = 1; // which log?
class ct
{
public:
ct& operator << (char);
ct& operator << (bool);
ct& operator << (const char*);
ct& operator << (const string&);
ct& operator << (int);
};
string sDebugText = "";
enum eSearch {hit, miss, veto};
enum eFocus {no_focus, user, cache};
enum eWordHits {no_word, text, CSV};
enum eBandUserTotals {nBUT_none, nBUT_notveto, nBUT_all};
enum eBandDomainTotals {nBDT_none, nBDT_all, nBDT_user};
enum eBandDomainIncludes {nBDI_notveto, nBDI_all};
// log a report options
tFilePos iRepStart = 0, // report from where
iRepEnd = 0; // report to where
int iRepColumns = 80, // columns of screen?
iRepCSVcols = 100; // columns of CSV target
bool bRepSplit = false, // split long lines
bRepShowSize = false, // indent for request size
bRepKeepExt = true, // remove innards to show .mp3 etc
bRepCacheReport = true;
string sRepFileName = "temp.txt", // report file name
sRepFilter = "", // filter report
sRepSeperator = "|", // for CSV
sRepFocus = "",
sRepBDTuser = "",
sRepTitle = "";
int iRepWordHits = text,
iRepBUT = nBUT_notveto,
iRepBDT = nBDT_all,
iRepBDI = nBDI_notveto,
iRepFocus = no_focus;
bool bLookupIP = true;
bool bAliases = false;
int iRepFast = 10000;
bool bRepMySort = true;
struct sRecordPointer
{
tByteTotal iBytes;
int iHits;
int iRecordNumber;
sRecordPointer operator= (const sRecordPointer&);
};
struct sListRecords
{
vector <sRecordPointer> vList;
enum eSortType {nSortHits, nSortBytes};
void Sort (eSortType nSelect);
void Empty();
};
struct sUserRecord
{
string sLoginName;
string sFullName;
};
struct sDomainRecord
{
string sDomainName;
};
struct rUserTotal
{
tByteTotal iBytes;
int iHits;
string sLoginName;
string sFullName;
rUserTotal operator= (const rUserTotal&);
};
struct rDomainTotal
{
tByteTotal iBytes;
int iHits;
string sDomain;
rDomainTotal operator= (const rDomainTotal&);
};
struct rAliasRecord
{
tIPnum iIPnum;
int iUserNum;
};
vector <rAliasRecord> vAliasList;
vector <string> vAliasUserName;
int iSortFlag = 0;
// story of recent activity by one user
class cUserHistory
{
public:
bool Run (const string&);
void CalcScreen();
bool Browse();
void AddHistory();
int AddHistoryNorth();
int AddHistorySouth();
void DisplayHistory();
void DisplayHelp();
void ZeroAll();
string sUser;
static const int nMaxRows = 200;
static const int nMaxNorth = 1000;
static const int nMaxSouth = 1000;
vector <tFilePos> vRequests;
tFilePos iOneUserFileSize, iNorthMark, iSouthMark, iSouthMarkEnd;
int iTotalRows, iSelectedAddress;
int iScreenHeight, iSelectedRow;
int iScreenStart, iLastScreenRow;
};
// tally of users' activity
class cUsersMode
{
public:
cUsersMode();
bool Enter();
bool Browse();
void DisplayPoints();
void DisplayFullNames();
void DisplayGreatestURLs();
void DisplayLastURLs();
void DisplayHeading (const string& sTitle);
void DisplayData (int iData);
void DisplayHelp();
void CalcScreen();
void AddData (tFilePos iFrom, tFilePos iTo);
void SortData();
void SortMenu();
const char* SortMode();
void AgeData (int iCurrentTime);
void FindFullNames();
void ZeroAll();
struct rUserHistory
{
string sUser, sFullName;
int iPoints, iBytes, iRequests, iURLsize;
tFilePos iGreatestURL, iLastURL;
time_t iLastTime;
void Zero()
{
sUser = sFullName = "";
iPoints = iBytes = iRequests = iURLsize = iLastTime = 0;
iGreatestURL = iLastURL = -1;
}
rUserHistory& operator= (const rUserHistory& aSrc)
{
sUser = aSrc.sUser;
sFullName = aSrc.sFullName;
iPoints = aSrc.iPoints;
iBytes = aSrc.iBytes;
iRequests = aSrc.iRequests;
iURLsize = aSrc.iURLsize;
iLastTime = aSrc.iLastTime;
iGreatestURL = aSrc.iGreatestURL;
iLastURL = aSrc.iLastURL;
return *this;
}
};
string LookupUser (const rUserHistory& aUser);
inline int CalcAeon (int iRough)
{
return int (iRough / iHistoryPeriod) * iHistoryPeriod;
}
enum eSM {nPoints = 0, nFullNames, nGreatest, nLast, nSMend} iScreenMode;
enum eSort {nSortN, nSortU, nSortP, nSortB, nSortR, nSortURL, nSortI}
iSortMode;
int iScreenStart, iSelectedRow, iTotalRows;
int iScreenHeight, iSelectedAddress, iLastScreenRow;
vector <rUserHistory> vHistory;
time_t iLastAdjustTime, iNextAdjustTime;
int iHistoryPeriod;
float fFadeFactor, fEntryFactor;
tFilePos iCurrentLogPos, iUsersFileSize;
bool bUsersMonitorMode;
bool bAcceptDenies;
};