1185 lines
25 KiB
C
1185 lines
25 KiB
C
/*
|
|
Copyright 2001-2018 John Wiseman G8BPQ
|
|
|
|
This file is part of LinBPQ/BPQ32.
|
|
|
|
LinBPQ/BPQ32 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
|
|
*/
|
|
|
|
// Mail and Chat Server for BPQ32 Packet Switch
|
|
//
|
|
// Housekeeping Module
|
|
|
|
#include "bpqmail.h"
|
|
|
|
char * APIENTRY GetBPQDirectory();
|
|
|
|
int LogAge = 7;
|
|
|
|
BOOL DeletetoRecycleBin = FALSE;
|
|
BOOL SuppressMaintEmail = FALSE;
|
|
BOOL GenerateTrafficReport = TRUE;
|
|
BOOL SaveRegDuringMaint = FALSE;
|
|
BOOL OverrideUnsent = FALSE;
|
|
BOOL SendNonDeliveryMsgs = TRUE;
|
|
VOID UpdateWP();
|
|
|
|
double PR = 30;
|
|
double PUR = 30;
|
|
double PF = 30;
|
|
double PNF = 30;
|
|
|
|
int BF = 30;
|
|
int BNF = 30;
|
|
//int AP;
|
|
//int AB;
|
|
int NTSD = 30;
|
|
int NTSF = 30;
|
|
int NTSU = 30;
|
|
|
|
char LTFROMString[2048];
|
|
char LTTOString[2048];
|
|
char LTATString[2048];
|
|
|
|
struct Override ** LTFROM;
|
|
struct Override ** LTTO;
|
|
struct Override ** LTAT;
|
|
|
|
int DeleteLogFiles();
|
|
|
|
VOID SendNonDeliveryMessage(struct MsgInfo * OldMsg, BOOL Forwarded, int Age);
|
|
int CreateWPMessage();
|
|
int DeleteRedundantMessages();
|
|
VOID CreateUserReport();
|
|
UCHAR * APIENTRY GetLogDirectory();
|
|
|
|
time_t LastHouseKeepingTime;
|
|
|
|
time_t LastTrafficTime;
|
|
|
|
void DeletetoRecycle(char * FN)
|
|
{
|
|
#ifdef WIN32
|
|
SHFILEOPSTRUCT FileOp;
|
|
|
|
FileOp.hwnd = NULL;
|
|
FileOp.wFunc = FO_DELETE;
|
|
FileOp.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR | FOF_ALLOWUNDO;
|
|
FileOp.pFrom = FN;
|
|
FileOp.pTo = NULL;
|
|
|
|
SHFileOperation(&FileOp);
|
|
#else
|
|
|
|
// On Linux move to Deleted under current directory
|
|
|
|
char newName[256];
|
|
char oldName[256];
|
|
|
|
strcpy(oldName, FN);
|
|
|
|
char * old = FN;
|
|
|
|
mkdir("Deleted", S_IRWXU | S_IRWXG | S_IRWXO); // Make sure exists
|
|
|
|
while(strchr(old, '/'))
|
|
{
|
|
old = strlop(old, '/');
|
|
}
|
|
sprintf(newName, "Deleted/%s", old);
|
|
|
|
rename(oldName, newName);
|
|
|
|
#endif
|
|
}
|
|
|
|
VOID FreeOverride(struct Override ** Hddr)
|
|
{
|
|
struct Override ** Save;
|
|
|
|
if (Hddr)
|
|
{
|
|
Save = Hddr;
|
|
while(Hddr[0])
|
|
{
|
|
free(Hddr[0]->Call);
|
|
free(Hddr[0]);
|
|
Hddr++;
|
|
}
|
|
free(Save);
|
|
}
|
|
}
|
|
|
|
VOID FreeOverrides()
|
|
{
|
|
FreeOverride(LTFROM);
|
|
FreeOverride(LTTO);
|
|
FreeOverride(LTAT);
|
|
}
|
|
|
|
VOID * GetOverrides(config_setting_t * group, char * ValueName)
|
|
{
|
|
char * ptr1;
|
|
char * MultiString = NULL;
|
|
char * ptr;
|
|
int Count = 0;
|
|
struct Override ** Value;
|
|
char * Val;
|
|
|
|
config_setting_t *setting;
|
|
|
|
Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values
|
|
Value[0] = NULL;
|
|
|
|
setting = config_setting_get_member (group, ValueName);
|
|
|
|
if (setting)
|
|
{
|
|
ptr = (char *)config_setting_get_string (setting);
|
|
|
|
while (ptr && strlen(ptr))
|
|
{
|
|
ptr1 = strchr(ptr, '|');
|
|
|
|
if (ptr1)
|
|
*(ptr1++) = 0;
|
|
|
|
Value = realloc(Value, (Count+2) * sizeof(void *));
|
|
Value[Count] = zalloc(sizeof(struct Override));
|
|
Val = strlop(ptr, ',');
|
|
if (Val == NULL)
|
|
break;
|
|
|
|
Value[Count]->Call = _strupr(_strdup(ptr));
|
|
Value[Count++]->Days = atoi(Val);
|
|
ptr = ptr1;
|
|
}
|
|
}
|
|
|
|
Value[Count] = NULL;
|
|
return Value;
|
|
}
|
|
|
|
VOID * RegGetOverrides(HKEY hKey, char * ValueName)
|
|
{
|
|
#ifdef LINBPQ
|
|
return NULL;
|
|
#else
|
|
int retCode,Type,Vallen;
|
|
char * MultiString;
|
|
int ptr, len;
|
|
int Count = 0;
|
|
struct Override ** Value;
|
|
char * Val;
|
|
|
|
|
|
Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values
|
|
|
|
Value[0] = NULL;
|
|
|
|
Vallen=0;
|
|
|
|
retCode = RegQueryValueEx(hKey, ValueName, 0, (ULONG *)&Type, NULL, (ULONG *)&Vallen);
|
|
|
|
if ((retCode != 0) || (Vallen == 0))
|
|
return FALSE;
|
|
|
|
MultiString = malloc(Vallen);
|
|
|
|
retCode = RegQueryValueEx(hKey, ValueName, 0,
|
|
(ULONG *)&Type,(UCHAR *)MultiString,(ULONG *)&Vallen);
|
|
|
|
ptr=0;
|
|
|
|
while (MultiString[ptr])
|
|
{
|
|
len=strlen(&MultiString[ptr]);
|
|
|
|
Value = realloc(Value, (Count+2) * sizeof(void *));
|
|
Value[Count] = zalloc(sizeof(struct Override));
|
|
Val = strlop(&MultiString[ptr], ',');
|
|
if (Val == NULL)
|
|
break;
|
|
|
|
Value[Count]->Call = _strupr(_strdup(&MultiString[ptr]));
|
|
Value[Count++]->Days = atoi(Val);
|
|
ptr+= (len + 1);
|
|
}
|
|
|
|
Value[Count] = NULL;
|
|
|
|
free(MultiString);
|
|
|
|
return Value;
|
|
#endif
|
|
}
|
|
|
|
int Removed;
|
|
int Killed;
|
|
int BIDSRemoved;
|
|
|
|
#ifndef LINBPQ
|
|
|
|
INT_PTR CALLBACK HKDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int Command;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_INITDIALOG:
|
|
|
|
SetDlgItemInt(hDlg, IDC_REMOVED, Removed, FALSE);
|
|
SetDlgItemInt(hDlg, IDC_KILLED, Killed, FALSE);
|
|
SetDlgItemInt(hDlg, IDC_LIVE, NumberofMessages - Killed, FALSE);
|
|
SetDlgItemInt(hDlg, IDC_TOTAL, NumberofMessages, FALSE);
|
|
SetDlgItemInt(hDlg, IDC_BIDSREMOVED, BIDSRemoved, FALSE);
|
|
SetDlgItemInt(hDlg, IDC_BIDSLEFT, NumberofBIDs, FALSE);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
Command = LOWORD(wParam);
|
|
|
|
switch (Command)
|
|
{
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
VOID DoHouseKeeping(BOOL Manual)
|
|
{
|
|
time_t NOW;
|
|
|
|
CreateUserReport();
|
|
|
|
UpdateWP();
|
|
|
|
DeleteLogFiles();
|
|
|
|
RemoveKilledMessages();
|
|
ExpireMessages();
|
|
|
|
GetSemaphore(&AllocSemaphore, 0);
|
|
ExpireBIDs();
|
|
FreeSemaphore(&AllocSemaphore);
|
|
|
|
if (LatestMsg > MaxMsgno)
|
|
{
|
|
GetSemaphore(&MsgNoSemaphore, 0);
|
|
GetSemaphore(&AllocSemaphore, 0);
|
|
|
|
Renumber_Messages();
|
|
|
|
FreeSemaphore(&AllocSemaphore);
|
|
FreeSemaphore(&MsgNoSemaphore);
|
|
}
|
|
|
|
if (!SuppressMaintEmail)
|
|
MailHousekeepingResults();
|
|
|
|
LastHouseKeepingTime = NOW = time(NULL);
|
|
|
|
SaveMessageDatabase();
|
|
|
|
SaveConfig(ConfigName);
|
|
GetConfig(ConfigName);
|
|
|
|
GetBadWordFile(); // Reread Badwords
|
|
|
|
#ifndef LINBPQ
|
|
|
|
if (Manual)
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_MAINTRESULTS), hWnd, HKDialogProc);
|
|
|
|
#endif
|
|
|
|
if (SendWP)
|
|
CreateWPMessage();
|
|
|
|
return;
|
|
}
|
|
|
|
VOID ExpireMessages()
|
|
{
|
|
struct MsgInfo * Msg;
|
|
int n;
|
|
time_t PRLimit;
|
|
time_t PURLimit;
|
|
time_t PFLimit;
|
|
time_t PNFLimit;
|
|
time_t BFLimit;
|
|
time_t BNFLimit;
|
|
time_t BLimit;
|
|
time_t NTSDLimit;
|
|
time_t NTSULimit;
|
|
time_t NTSFLimit;
|
|
|
|
struct Override ** Calls;
|
|
|
|
time_t now = time(NULL);
|
|
time_t Future = now + (7 * 86400);
|
|
|
|
Killed = 0;
|
|
|
|
PRLimit = now - PR*86400;
|
|
PURLimit = now - PUR*86400;
|
|
PFLimit = now - PF*86400;
|
|
PNFLimit = now - PNF*86400;
|
|
BFLimit = now - BF*86400;
|
|
BNFLimit = now - BNF*86400;
|
|
|
|
if (NTSU == 0)
|
|
{
|
|
// Assume all unset
|
|
|
|
NTSD = 30;
|
|
NTSU = 30;
|
|
NTSF = 30;
|
|
}
|
|
|
|
NTSDLimit = now - NTSD*86400;
|
|
NTSULimit = now - NTSU*86400;
|
|
NTSFLimit = now - NTSF*86400;
|
|
|
|
for (n = 1; n <= NumberofMessages; n++)
|
|
{
|
|
Msg = MsgHddrPtr[n];
|
|
|
|
// If from the future, Kill it
|
|
|
|
if (Msg->datecreated > Future)
|
|
{
|
|
KillMsg(Msg);
|
|
continue;
|
|
}
|
|
|
|
switch (Msg->type)
|
|
{
|
|
case 'P':
|
|
|
|
switch (Msg->status)
|
|
{
|
|
case 'N':
|
|
case 'H':
|
|
|
|
// Is it unforwarded or unread?
|
|
|
|
if (memcmp(Msg->fbbs, zeros, NBMASK) == 0)
|
|
{
|
|
if (Msg->datecreated < PURLimit)
|
|
{
|
|
if (SendNonDeliveryMsgs)
|
|
SendNonDeliveryMessage(Msg, TRUE, PUR);
|
|
|
|
KillMsg(Msg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Msg->datecreated < PNFLimit)
|
|
{
|
|
if (SendNonDeliveryMsgs)
|
|
SendNonDeliveryMessage(Msg, FALSE, PNF);
|
|
|
|
KillMsg(Msg);
|
|
}
|
|
}
|
|
continue;
|
|
|
|
case 'F':
|
|
|
|
if (Msg->datechanged < PFLimit) KillMsg(Msg);
|
|
|
|
continue;
|
|
|
|
case 'Y':
|
|
|
|
if (Msg->datechanged < PRLimit) KillMsg(Msg);
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case 'T':
|
|
|
|
switch (Msg->status)
|
|
{
|
|
case 'F':
|
|
|
|
if (Msg->datechanged < NTSFLimit)
|
|
KillMsg(Msg);
|
|
|
|
continue;
|
|
|
|
case 'D':
|
|
|
|
if (Msg->datechanged < NTSDLimit)
|
|
KillMsg(Msg);
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
if (Msg->datecreated < NTSULimit)
|
|
{
|
|
if (SendNonDeliveryMsgs)
|
|
SendNonDeliveryMessage(Msg, TRUE, NTSU);
|
|
|
|
KillMsg(Msg);
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
case 'B':
|
|
|
|
BLimit = BF;
|
|
BNFLimit = now - BNF*86400;
|
|
|
|
// Check FROM Overrides
|
|
|
|
if (LTFROM)
|
|
{
|
|
Calls = LTFROM;
|
|
|
|
while(Calls[0])
|
|
{
|
|
if (strcmp(Calls[0]->Call, Msg->from) == 0)
|
|
{
|
|
BLimit = Calls[0]->Days;
|
|
goto gotit;
|
|
}
|
|
Calls++;
|
|
}
|
|
}
|
|
|
|
// Check TO Overrides
|
|
|
|
if (LTTO)
|
|
{
|
|
Calls = LTTO;
|
|
|
|
while(Calls[0])
|
|
{
|
|
if (strcmp(Calls[0]->Call, Msg->to) == 0)
|
|
{
|
|
BLimit = Calls[0]->Days;
|
|
goto gotit;
|
|
}
|
|
Calls++;
|
|
}
|
|
}
|
|
|
|
// Check AT Overrides
|
|
|
|
if (LTAT)
|
|
{
|
|
Calls = LTAT;
|
|
|
|
while(Calls[0])
|
|
{
|
|
if (strcmp(Calls[0]->Call, Msg->via) == 0)
|
|
{
|
|
BLimit = Calls[0]->Days;
|
|
goto gotit;
|
|
}
|
|
Calls++;
|
|
}
|
|
}
|
|
|
|
gotit:
|
|
|
|
BFLimit = now - BLimit*86400;
|
|
|
|
if (OverrideUnsent)
|
|
if (BLimit != BF) // Have we an override?
|
|
BNFLimit = BFLimit;
|
|
|
|
switch (Msg->status)
|
|
{
|
|
case '$':
|
|
case 'N':
|
|
case ' ':
|
|
case 'H':
|
|
|
|
|
|
if (Msg->datecreated < BNFLimit)
|
|
KillMsg(Msg);
|
|
break;
|
|
|
|
case 'F':
|
|
case 'Y':
|
|
|
|
if (Msg->datecreated < BFLimit)
|
|
KillMsg(Msg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID KillMsg(struct MsgInfo * Msg)
|
|
{
|
|
FlagAsKilled(Msg, FALSE);
|
|
Killed++;
|
|
}
|
|
|
|
BOOL RemoveKilledMessages()
|
|
{
|
|
struct MsgInfo * Msg;
|
|
struct MsgInfo ** NewMsgHddrPtr;
|
|
char MsgFile[MAX_PATH];
|
|
int i, n;
|
|
|
|
Removed = 0;
|
|
|
|
GetSemaphore(&MsgNoSemaphore, 0);
|
|
GetSemaphore(&AllocSemaphore, 0);
|
|
|
|
FirstMessageIndextoForward = 0;
|
|
|
|
NewMsgHddrPtr = zalloc((NumberofMessages+1) * sizeof(void *));
|
|
NewMsgHddrPtr[0] = MsgHddrPtr[0]; // Copy Control Record
|
|
|
|
i = 0;
|
|
|
|
for (n = 1; n <= NumberofMessages; n++)
|
|
{
|
|
Msg = MsgHddrPtr[n];
|
|
|
|
if (Msg->status == 'K')
|
|
{
|
|
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes%c", MailDir, Msg->number, 0);
|
|
if (DeletetoRecycleBin)
|
|
DeletetoRecycle(MsgFile);
|
|
else
|
|
DeleteFile(MsgFile);
|
|
|
|
MsgnotoMsg[Msg->number] = NULL;
|
|
free(Msg);
|
|
|
|
Removed++;
|
|
}
|
|
else
|
|
{
|
|
NewMsgHddrPtr[++i] = Msg;
|
|
if (memcmp(Msg->fbbs, zeros, NBMASK) != 0)
|
|
{
|
|
if (FirstMessageIndextoForward == 0)
|
|
FirstMessageIndextoForward = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
NumberofMessages = i;
|
|
NewMsgHddrPtr[0]->number = i;
|
|
|
|
if (FirstMessageIndextoForward == 0)
|
|
FirstMessageIndextoForward = NumberofMessages;
|
|
|
|
free(MsgHddrPtr);
|
|
|
|
MsgHddrPtr = NewMsgHddrPtr;
|
|
|
|
FreeSemaphore(&MsgNoSemaphore);
|
|
FreeSemaphore(&AllocSemaphore);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#define MESSAGE_NUMBER_MAX 100000
|
|
|
|
VOID Renumber_Messages()
|
|
{
|
|
int * NewNumber = (int *)0;
|
|
struct MsgInfo * Msg;
|
|
struct UserInfo * user = NULL;
|
|
char OldMsgFile[MAX_PATH];
|
|
char NewMsgFile[MAX_PATH];
|
|
int j, lastmsg, result;
|
|
|
|
int i, n, s;
|
|
|
|
s = sizeof(int)* MESSAGE_NUMBER_MAX;
|
|
|
|
NewNumber = malloc(s);
|
|
|
|
if (!NewNumber) return;
|
|
|
|
DeleteRedundantMessages(); // Make sure there aren't any old mail files, or renumber may fail
|
|
|
|
memset(NewNumber, 0, s);
|
|
|
|
for (i = 0; i < 100000; i++)
|
|
{
|
|
MsgnotoMsg[i] = NULL;
|
|
}
|
|
|
|
i = 0; // New Message Number
|
|
|
|
for (n = 1; n <= NumberofMessages; n++)
|
|
{
|
|
Msg = MsgHddrPtr[n];
|
|
|
|
NewNumber[Msg->number] = ++i; // Save so we can update users' last listed count
|
|
|
|
// New will always be >= old unless something has gone horribly wrong,
|
|
// so can rename in place without risk of losing a message
|
|
|
|
if (Msg->number < i)
|
|
{
|
|
#ifndef LINBPQ
|
|
MessageBox(MainWnd, "Invalid message number detected, quitting", "BPQMailChat", MB_OK);
|
|
#else
|
|
Debugprintf("Invalid message number detected, quitting");
|
|
#endif
|
|
SaveMessageDatabase();
|
|
if (NewNumber) free(NewNumber);
|
|
|
|
return;
|
|
}
|
|
|
|
if (Msg->number != i)
|
|
{
|
|
sprintf(OldMsgFile, "%s/m_%06d.mes", MailDir, Msg->number);
|
|
sprintf(NewMsgFile, "%s/m_%06d.mes", MailDir, i);
|
|
result = rename(OldMsgFile, NewMsgFile);
|
|
if (result)
|
|
{
|
|
char Errmsg[100];
|
|
sprintf(Errmsg, "Could not rename message no %d to %d, quitting", Msg->number, i);
|
|
#ifndef LINBPQ
|
|
MessageBox(MainWnd,Errmsg , "BPQMailChat", MB_OK);
|
|
#else
|
|
Debugprintf(Errmsg);
|
|
#endif
|
|
SaveMessageDatabase();
|
|
if (NewNumber) free(NewNumber);
|
|
|
|
return;
|
|
}
|
|
Msg->number = i;
|
|
MsgnotoMsg[i] = Msg;
|
|
}
|
|
|
|
}
|
|
|
|
for (n = 0; n <= NumberofUsers; n++)
|
|
{
|
|
user = UserRecPtr[n];
|
|
lastmsg = user->lastmsg;
|
|
|
|
if (lastmsg <= 0)
|
|
user->lastmsg = 0;
|
|
else
|
|
{
|
|
j = NewNumber[lastmsg];
|
|
|
|
if (j == 0)
|
|
{
|
|
// Last listed has gone. Find next above
|
|
|
|
while(++lastmsg < 65536)
|
|
{
|
|
if (NewNumber[lastmsg] != 0)
|
|
{
|
|
user->lastmsg = NewNumber[lastmsg];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Not found, so use latest
|
|
|
|
user->lastmsg = i;
|
|
break;
|
|
}
|
|
user->lastmsg = NewNumber[lastmsg];
|
|
}
|
|
}
|
|
|
|
MsgHddrPtr[0]->length = LatestMsg = i;
|
|
|
|
SaveMessageDatabase();
|
|
SaveUserDatabase();
|
|
|
|
if (NewNumber) free(NewNumber);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BOOL ExpireBIDs()
|
|
{
|
|
BIDRec * BID;
|
|
BIDRec ** NewBIDRecPtr;
|
|
unsigned short now = LOWORD(time(NULL)/86400);
|
|
|
|
int i, n;
|
|
|
|
NewBIDRecPtr = zalloc((NumberofBIDs + 1) * sizeof(BIDRec));
|
|
NewBIDRecPtr[0] = BIDRecPtr[0]; // Copy Control Record
|
|
|
|
i = 0;
|
|
|
|
for (n = 1; n <= NumberofBIDs; n++)
|
|
{
|
|
BID = BIDRecPtr[n];
|
|
|
|
// Debugprintf("%d %d", BID->u.timestamp, now - BID->u.timestamp);
|
|
|
|
if ((now - BID->u.timestamp) < BidLifetime)
|
|
NewBIDRecPtr[++i] = BID;
|
|
}
|
|
|
|
BIDSRemoved = NumberofBIDs - i;
|
|
|
|
NumberofBIDs = i;
|
|
NewBIDRecPtr[0]->u.msgno = i;
|
|
|
|
free(BIDRecPtr);
|
|
|
|
BIDRecPtr = NewBIDRecPtr;
|
|
|
|
SaveBIDDatabase();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID MailHousekeepingResults()
|
|
{
|
|
int Length=0;
|
|
char * MailBuffer = malloc(10000);
|
|
|
|
Length += sprintf(&MailBuffer[Length], "Killed Messages Removed %d\r\n", Removed);
|
|
Length += sprintf(&MailBuffer[Length], "Messages Killed %d\r\n", Killed);
|
|
Length += sprintf(&MailBuffer[Length], "Live Messages %d\r\n", NumberofMessages - Killed);
|
|
Length += sprintf(&MailBuffer[Length], "Total Messages %d\r\n", NumberofMessages);
|
|
Length += sprintf(&MailBuffer[Length], "BIDs Removed %d\r\n", BIDSRemoved);
|
|
Length += sprintf(&MailBuffer[Length], "BIDs Left %d\r\n", NumberofBIDs);
|
|
|
|
SendMessageToSYSOP("Housekeeping Results", MailBuffer, Length);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
|
|
extern UCHAR LogDirectory[260];
|
|
|
|
int DeleteLogFiles()
|
|
{
|
|
WIN32_FIND_DATA ffd;
|
|
|
|
char szDir[MAX_PATH];
|
|
char File[MAX_PATH];
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
DWORD dwError=0;
|
|
LARGE_INTEGER ft;
|
|
time_t now = time(NULL);
|
|
int Age;
|
|
UCHAR * ptr;
|
|
|
|
// Prepare string for use with FindFile functions. First, copy the
|
|
// string to a buffer, then append '\*' to the directory name.
|
|
|
|
|
|
ptr = GetLogDirectory();
|
|
|
|
strcpy(szDir, ptr);
|
|
strcat(szDir, "/logs/Log_*.txt");
|
|
|
|
// Find the first file in the directory.
|
|
|
|
hFind = FindFirstFile(szDir, &ffd);
|
|
|
|
if (INVALID_HANDLE_VALUE == hFind)
|
|
{
|
|
return dwError;
|
|
}
|
|
|
|
// List all the files in the directory with some info about them.
|
|
|
|
do
|
|
{
|
|
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
OutputDebugString(ffd.cFileName);
|
|
}
|
|
else
|
|
{
|
|
ft.HighPart = ffd.ftCreationTime.dwHighDateTime;
|
|
ft.LowPart = ffd.ftCreationTime.dwLowDateTime;
|
|
|
|
ft.QuadPart -= 116444736000000000;
|
|
ft.QuadPart /= 10000000;
|
|
|
|
Age = (int)((now - ft.LowPart) / 86400);
|
|
|
|
if (Age > LogAge)
|
|
{
|
|
sprintf(File, "%s/logs/%s%c", GetLogDirectory(), ffd.cFileName, 0);
|
|
if (DeletetoRecycleBin)
|
|
DeletetoRecycle(File);
|
|
else
|
|
DeleteFile(File);
|
|
}
|
|
}
|
|
}
|
|
while (FindNextFile(hFind, &ffd) != 0);
|
|
|
|
dwError = GetLastError();
|
|
|
|
FindClose(hFind);
|
|
return dwError;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <dirent.h>
|
|
|
|
int Filter(const struct dirent * dir)
|
|
{
|
|
return memcmp(dir->d_name, "log", 3) == 0 && strstr(dir->d_name, ".txt");
|
|
}
|
|
|
|
int DeleteLogFiles()
|
|
{
|
|
struct dirent **namelist;
|
|
int n;
|
|
struct stat STAT;
|
|
time_t now = time(NULL);
|
|
int Age = 0, res;
|
|
char FN[256];
|
|
|
|
n = scandir("logs", &namelist, Filter, alphasort);
|
|
|
|
if (n < 0)
|
|
perror("scandir");
|
|
else
|
|
{
|
|
while(n--)
|
|
{
|
|
sprintf(FN, "logs/%s", namelist[n]->d_name);
|
|
if (stat(FN, &STAT) == 0)
|
|
{
|
|
Age = (now - STAT.st_mtime) / 86400;
|
|
|
|
if (Age > LogAge)
|
|
{
|
|
printf("Deleting %s\n", FN);
|
|
unlink(FN);
|
|
}
|
|
}
|
|
free(namelist[n]);
|
|
}
|
|
free(namelist);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID SendNonDeliveryMessage(struct MsgInfo * OldMsg, BOOL Unread, int Age)
|
|
{
|
|
struct MsgInfo * Msg;
|
|
BIDRec * BIDRec;
|
|
char MailBuffer[1000];
|
|
char MsgFile[MAX_PATH];
|
|
FILE * hFile;
|
|
int WriteLen=0;
|
|
char From[100];
|
|
char * Via;
|
|
struct UserInfo * FromUser;
|
|
|
|
// Try to create a from Address. ( ? check RMS)
|
|
|
|
strcpy(From, OldMsg->from);
|
|
|
|
if (strcmp(From, "SYSTEM") == 0)
|
|
return; // Don't send non-deliverys SYSTEM messages
|
|
|
|
// Dont send NDN for NDN
|
|
|
|
if (strcmp(OldMsg->title, "Non-delivery Notification") == 0)
|
|
return;
|
|
|
|
FromUser = LookupCall(OldMsg->from);
|
|
|
|
if (FromUser)
|
|
{
|
|
if (FromUser->HomeBBS[0])
|
|
sprintf(From, "%s@%s", OldMsg->from, FromUser->HomeBBS);
|
|
else
|
|
sprintf(From, "%s@%s", OldMsg->from, BBSName);
|
|
}
|
|
else
|
|
{
|
|
WPRecP WP = LookupWP(OldMsg->from);
|
|
|
|
if (WP)
|
|
sprintf(From, "%s@%s", OldMsg->from, WP->first_homebbs);
|
|
}
|
|
|
|
Msg = AllocateMsgRecord();
|
|
GetSemaphore(&MsgNoSemaphore, 0);
|
|
Msg->number = ++LatestMsg;
|
|
MsgnotoMsg[Msg->number] = Msg;
|
|
|
|
FreeSemaphore(&MsgNoSemaphore);
|
|
|
|
strcpy(Msg->from, SYSOPCall);
|
|
|
|
Via = strlop(From, '@');
|
|
|
|
strcpy(Msg->to, From);
|
|
if (Via)
|
|
strcpy(Msg->via, Via);
|
|
|
|
if (strcmp(From, "RMS:") == 0)
|
|
{
|
|
strcpy(Msg->to, "RMS");
|
|
strcpy(Msg->via, OldMsg->emailfrom);
|
|
}
|
|
|
|
if (strcmp(From, "smtp:") == 0)
|
|
{
|
|
Msg->to[0] = 0;
|
|
strcpy(Msg->via, OldMsg->emailfrom);
|
|
}
|
|
|
|
if (Msg->to[0] == 0)
|
|
return;
|
|
|
|
strcpy(Msg->title, "Non-delivery Notification");
|
|
|
|
if (Unread)
|
|
Msg->length = sprintf(MailBuffer, "Your Message ID %s Subject %s to %s has not been read for %d days.\r\nMessage had been deleted.\r\n", OldMsg->bid, OldMsg->title, OldMsg->to, Age);
|
|
else
|
|
Msg->length = sprintf(MailBuffer, "Your Message ID %s Subject %s to %s could not be delivered in %d days.\r\nMessage had been deleted.\r\n", OldMsg->bid, OldMsg->title, OldMsg->to, Age);
|
|
|
|
|
|
Msg->type = 'P';
|
|
Msg->status = 'N';
|
|
Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
|
|
|
|
sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName);
|
|
|
|
BIDRec = AllocateBIDRecord();
|
|
strcpy(BIDRec->BID, Msg->bid);
|
|
BIDRec->mode = Msg->type;
|
|
BIDRec->u.msgno = LOWORD(Msg->number);
|
|
BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
|
|
|
|
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
|
|
|
|
hFile = fopen(MsgFile, "wb");
|
|
|
|
if (hFile)
|
|
{
|
|
fwrite(MailBuffer, 1, Msg->length, hFile);
|
|
fclose(hFile);
|
|
}
|
|
|
|
MatchMessagetoBBSList(Msg, NULL);
|
|
}
|
|
|
|
VOID CreateBBSTrafficReport()
|
|
{
|
|
struct UserInfo * User;
|
|
int i, n;
|
|
char Line[200];
|
|
int len;
|
|
char File[MAX_PATH];
|
|
FILE * hFile;
|
|
time_t NOW = time(NULL);
|
|
|
|
int ConnectsIn;
|
|
int ConnectsOut;
|
|
// int MsgsReceived;
|
|
// int MsgsSent;
|
|
// int MsgsRejectedIn;
|
|
// int MsgsRejectedOut;
|
|
// int BytesForwardedIn;
|
|
// int BytesForwardedOut;
|
|
int TotMsgsReceived[4] = {0,0,0,0};
|
|
int TotMsgsSent[4] = {0,0,0,0};
|
|
|
|
int TotBytesForwardedIn[4] = {0,0,0,0};
|
|
int TotBytesForwardedOut[4] = {0,0,0,0};
|
|
|
|
char MsgsIn[80];
|
|
char MsgsOut[80];
|
|
char BytesIn[80];
|
|
char BytesOut[80];
|
|
char RejIn[80];
|
|
char RejOut[80];
|
|
|
|
struct tm tm;
|
|
struct tm last;
|
|
|
|
memcpy(&tm, gmtime(&NOW), sizeof(tm));
|
|
memcpy(&last, gmtime((const time_t *)&LastTrafficTime), sizeof(tm));
|
|
|
|
sprintf(File, "%s/Traffic_%02d%02d%02d.txt", BaseDir, tm.tm_year-100, tm.tm_mon+1, tm.tm_mday);
|
|
|
|
hFile = fopen(File, "wb");
|
|
|
|
if (hFile == NULL)
|
|
{
|
|
Debugprintf("Failed to create traffic.txt");
|
|
return;
|
|
}
|
|
|
|
len = sprintf(Line, " Traffic Report for %s From: %04d/%02d/%02d %02d:%02dz To: %04d/%02d/%02d %02d:%02dz\r\n",
|
|
BBSName, last.tm_year+1900, last.tm_mon+1, last.tm_mday, last.tm_hour, last.tm_min,
|
|
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min);
|
|
|
|
fwrite(Line, 1, len, hFile);
|
|
|
|
len = sprintf(Line, " Call Connects Connects Messages Messages Bytes Bytes Rejected Rejected\r\n");
|
|
fwrite(Line, 1, len, hFile);
|
|
len = sprintf(Line, " In Out Rxed(P/B/T) Sent Rxed Sent In Out\r\n\r\n");
|
|
|
|
fwrite(Line, 1, len, hFile);
|
|
|
|
for (i=1; i <= NumberofUsers; i++)
|
|
{
|
|
User = UserRecPtr[i];
|
|
|
|
ConnectsIn = User->Total.ConnectsIn - User->Last.ConnectsIn;
|
|
ConnectsOut = User->Total.ConnectsOut - User->Last.ConnectsOut;
|
|
|
|
/*
|
|
MsgsReceived = MsgsSent = MsgsRejectedIn = MsgsRejectedOut = BytesForwardedIn = BytesForwardedOut = 0;
|
|
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
MsgsReceived += User->Total.MsgsReceived[n] - User->Last.MsgsReceived[n];
|
|
MsgsSent += User->Total.MsgsSent[n] - User->Last.MsgsSent[n];
|
|
BytesForwardedIn += User->Total.BytesForwardedIn[n] - User->Last.BytesForwardedIn[n];
|
|
BytesForwardedOut += User->Total.BytesForwardedOut[n] - User->Last.BytesForwardedOut[n];
|
|
MsgsRejectedIn += User->Total.MsgsRejectedIn[n] - User->Last.MsgsRejectedIn[n];
|
|
MsgsRejectedOut += User->Total.MsgsRejectedOut[n] - User->Last.MsgsRejectedOut[n];
|
|
}
|
|
|
|
len = sprintf(Line, "%s %-7s %5d %8d %10d %10d %10d %10d %10d %10d\r\n",
|
|
(User->flags & F_BBS)? "(B)": " ",
|
|
User->Call, ConnectsIn,
|
|
ConnectsOut,
|
|
MsgsReceived,
|
|
MsgsSent,
|
|
BytesForwardedIn,
|
|
BytesForwardedOut,
|
|
MsgsRejectedIn,
|
|
MsgsRejectedOut);
|
|
*/
|
|
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
TotMsgsReceived[n] += User->Total.MsgsReceived[n] - User->Last.MsgsReceived[n];
|
|
TotMsgsSent[n] += User->Total.MsgsSent[n] - User->Last.MsgsSent[n];
|
|
|
|
TotBytesForwardedIn[n] += User->Total.BytesForwardedIn[n] - User->Last.BytesForwardedIn[n];
|
|
TotBytesForwardedOut[n] += User->Total.BytesForwardedOut[n] - User->Last.BytesForwardedOut[n];
|
|
}
|
|
|
|
sprintf(MsgsIn,"%d/%d/%d", User->Total.MsgsReceived[1] - User->Last.MsgsReceived[1],
|
|
User->Total.MsgsReceived[2] - User->Last.MsgsReceived[2],
|
|
User->Total.MsgsReceived[3] - User->Last.MsgsReceived[3]);
|
|
|
|
sprintf(MsgsOut,"%d/%d/%d", User->Total.MsgsSent[1] - User->Last.MsgsSent[1],
|
|
User->Total.MsgsSent[2] - User->Last.MsgsSent[2],
|
|
User->Total.MsgsSent[3] - User->Last.MsgsSent[3]);
|
|
|
|
sprintf(BytesIn,"%d/%d/%d", User->Total.BytesForwardedIn[1] - User->Last.BytesForwardedIn[1],
|
|
User->Total.BytesForwardedIn[2] - User->Last.BytesForwardedIn[2],
|
|
User->Total.BytesForwardedIn[3] - User->Last.BytesForwardedIn[3]);
|
|
|
|
sprintf(BytesOut,"%d/%d/%d", User->Total.BytesForwardedOut[1] - User->Last.BytesForwardedOut[1],
|
|
User->Total.BytesForwardedOut[2] - User->Last.BytesForwardedOut[2],
|
|
User->Total.BytesForwardedOut[3] - User->Last.BytesForwardedOut[3]);
|
|
|
|
sprintf(RejIn,"%d/%d/%d", User->Total.MsgsRejectedIn[1] - User->Last.MsgsRejectedIn[1],
|
|
User->Total.MsgsRejectedIn[2] - User->Last.MsgsRejectedIn[2],
|
|
User->Total.MsgsRejectedIn[3] - User->Last.MsgsRejectedIn[3]);
|
|
|
|
sprintf(RejOut,"%d/%d/%d", User->Total.MsgsRejectedOut[1] - User->Last.MsgsRejectedOut[1],
|
|
User->Total.MsgsRejectedOut[2] - User->Last.MsgsRejectedOut[2],
|
|
User->Total.MsgsRejectedOut[3] - User->Last.MsgsRejectedOut[3]);
|
|
|
|
len = sprintf(Line, "%s %-7s %5d %8d%16s%16s%16s%16s%16s%16s\r\n",
|
|
(User->flags & F_BBS)? "(B)": " ",
|
|
User->Call, ConnectsIn,
|
|
ConnectsOut,
|
|
MsgsIn,
|
|
MsgsOut,
|
|
BytesIn,
|
|
BytesOut,
|
|
RejIn,
|
|
RejOut);
|
|
|
|
fwrite(Line, 1, len, hFile);
|
|
|
|
User->Last.ConnectsIn = User->Total.ConnectsIn;
|
|
User->Last.ConnectsOut = User->Total.ConnectsOut;
|
|
|
|
for (n = 0; n < 4; n++)
|
|
{
|
|
User->Last.MsgsReceived[n] = User->Total.MsgsReceived[n];
|
|
User->Last.MsgsSent[n] = User->Total.MsgsSent[n];
|
|
User->Last.BytesForwardedIn[n] = User->Total.BytesForwardedIn[n];
|
|
User->Last.BytesForwardedOut[n] = User->Total.BytesForwardedOut[n];
|
|
User->Last.MsgsRejectedIn[n] = User->Total.MsgsRejectedIn[n];
|
|
User->Last.MsgsRejectedOut[n] = User->Total.MsgsRejectedOut[n];
|
|
}
|
|
|
|
}
|
|
|
|
sprintf(MsgsIn,"%d/%d/%d", TotMsgsReceived[1], TotMsgsReceived[2], TotMsgsReceived[3]);
|
|
|
|
sprintf(MsgsOut,"%d/%d/%d", TotMsgsSent[1], TotMsgsSent[2], TotMsgsSent[3]);
|
|
|
|
sprintf(BytesIn,"%d/%d/%d", TotBytesForwardedIn[1], TotBytesForwardedIn[2], TotBytesForwardedIn[3]);
|
|
|
|
sprintf(BytesOut,"%d/%d/%d", TotBytesForwardedOut[1], TotBytesForwardedOut[2], TotBytesForwardedOut[3]);
|
|
|
|
len = sprintf(Line, "\r\n Totals %s Messages In %s Messages Out %s"
|
|
" Bytes In %s Bytes Out\r\n", MsgsIn, MsgsOut, BytesIn, BytesOut);
|
|
|
|
fwrite(Line, 1, len, hFile);
|
|
|
|
SaveConfig(ConfigName);
|
|
GetConfig(ConfigName);
|
|
|
|
SaveUserDatabase();
|
|
fclose(hFile);
|
|
}
|