1190 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1190 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
 | |
| 
 | |
| 
 | |
| 
 | |
| #define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__)
 | |
| 
 | |
| 
 | |
| #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 - (time_t)PR*86400;
 | |
| 	PURLimit = now -(time_t)PUR*86400;
 | |
| 	PFLimit = now - (time_t)PF*86400;
 | |
| 	PNFLimit = now - (time_t)PNF*86400;
 | |
| 	BFLimit = now - (time_t)BF*86400;
 | |
| 	BNFLimit = now -(time_t) 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, (int)PUR);
 | |
| 
 | |
| 						KillMsg(Msg);
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if (Msg->datecreated < PNFLimit)
 | |
| 					{
 | |
| 						if (SendNonDeliveryMsgs) 
 | |
| 							SendNonDeliveryMessage(Msg, FALSE, (int)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);
 | |
| }
 |