#define WINVER 0x500
#include <windows.h>
#include <string.h>
#include <winnt.h>

#ifdef __cplusplus
extern "C" {
#endif

#define VERSION "1.01"

#define AUTHINFO \
"System Info DLL for mIRC, v" VERSION " (c) 1999-2000 DragonZap, dragonzap1@aol.com; " \
	"Filesystem/memory info idea by Tritian"

int FAR PASCAL GetSpaceInfo(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	char *Disk=strchr(data,' ');
	if (Disk == NULL)
		return 1;
	Disk[0]=0;
	Disk++;
	if ((Disk[0] == '\\') && (Disk[1] == '\\') && (Disk[strlen(Disk)-1] != '\\'))
		strcat(Disk,"\\");
	ULARGE_INTEGER ignore;
	ULARGE_INTEGER Space;
	BOOL Success = false;
	if (!stricmp(data,"allowed")) { Success = GetDiskFreeSpaceEx(Disk,&Space,&ignore,NULL); }
	else if (!stricmp(data,"total")) { Success =  GetDiskFreeSpaceEx(Disk,&ignore,&Space,NULL); }
	else if (!stricmp(data,"free")) { Success = GetDiskFreeSpaceEx(Disk,&ignore,&ignore,&Space); }
	if (!Success)
		return 1;
	_ui64toa(Space.QuadPart,data,10);
	return 3;
}

int FAR PASCAL GetClusterInfo(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	char *Disk=strchr(data,' ');
	if (Disk == NULL)
		return 1;
	Disk[0]=0;
	Disk++;
	if ((Disk[0] == '\\') && (Disk[1] == '\\') && (Disk[strlen(Disk)-1] != '\\'))
		strcat(Disk,"\\");
	DWORD SPC;	// Sectors Per Cluster
	DWORD BPS;	// Bytes Per Sector
	DWORD FC;	// Free Clusters
	DWORD TC;	// Total Clusters
	
	if (!GetDiskFreeSpace(Disk,&SPC,&BPS,&FC,&TC))
		return 1;
	
	if (!stricmp(data,"sector")) { itoa(SPC,data,10); }
	else if (!stricmp(data,"bps")) { itoa(BPS,data,10); }
	else if (!stricmp(data,"free")) { itoa(FC,data,10); }
	else if (!stricmp(data,"total")) { itoa(TC,data,10); }
	else { return 1; }
	return 3;
}

int FAR PASCAL GetFileAttr(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	DWORD Attr = GetFileAttributes(data);
	if (Attr == 0xffffffff)
		return 1;
	data[0]=0;
#define TESTBIT(cst,letter) if (Attr & cst) strcat(data,#letter)

	TESTBIT(FILE_ATTRIBUTE_ARCHIVE,a);
	TESTBIT(FILE_ATTRIBUTE_COMPRESSED,c);
	TESTBIT(FILE_ATTRIBUTE_DIRECTORY,d);
	TESTBIT(FILE_ATTRIBUTE_ENCRYPTED,e);
	TESTBIT(FILE_ATTRIBUTE_SPARSE_FILE,f);
	TESTBIT(FILE_ATTRIBUTE_HIDDEN,h);
	TESTBIT(FILE_ATTRIBUTE_NORMAL,n);
	TESTBIT(FILE_ATTRIBUTE_OFFLINE,o);
	TESTBIT(FILE_ATTRIBUTE_REPARSE_POINT,p);
	TESTBIT(FILE_ATTRIBUTE_READONLY,r);
	TESTBIT(FILE_ATTRIBUTE_SYSTEM,s);
	TESTBIT(FILE_ATTRIBUTE_TEMPORARY,t);

#undef TESTBIT

	return 3;
}

int FAR PASCAL SetFileAttr(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	char *FileName = strchr(data,' ');
	
	if (FileName == NULL)
		return 1;

	FileName[0] = 0;
	FileName++;
	DWORD Attr = GetFileAttributes(FileName);
	if (Attr == 0xffffffff)
		return 1;
	int curchar;
	int alen = strlen(data);
	for(curchar=0;curchar<alen;curchar++) {
		data[curchar]=tolower(data[curchar]);
		switch(data[curchar])
		{
#define ATTRCASE(cst,letter) case letter: Attr |= cst; break
	ATTRCASE(FILE_ATTRIBUTE_ARCHIVE,'a');
	ATTRCASE(FILE_ATTRIBUTE_COMPRESSED,'c');
	ATTRCASE(FILE_ATTRIBUTE_DIRECTORY,'d');
	ATTRCASE(FILE_ATTRIBUTE_ENCRYPTED,'e');
	ATTRCASE(FILE_ATTRIBUTE_SPARSE_FILE,'f');
	ATTRCASE(FILE_ATTRIBUTE_HIDDEN,'h');
	ATTRCASE(FILE_ATTRIBUTE_OFFLINE,'o');
	ATTRCASE(FILE_ATTRIBUTE_REPARSE_POINT,'p');
	ATTRCASE(FILE_ATTRIBUTE_READONLY,'r');
	ATTRCASE(FILE_ATTRIBUTE_SYSTEM,'s');
	ATTRCASE(FILE_ATTRIBUTE_TEMPORARY,'t');			
#undef ATTRCASE
		case 'n':
			Attr = FILE_ATTRIBUTE_NORMAL;
		}
		if (data[curchar] != 'n')
			data[curchar] = data[curchar] & !FILE_ATTRIBUTE_NORMAL;
	}

	SetFileAttributes(FileName,Attr);
	return 1;
}

int FAR PASCAL GetTitle(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	char Buf[900];
	if (GetFileTitle(data,Buf,899))
		return 1;
	strcpy(data,Buf);
	return 3;
}

int FAR PASCAL GetVolumeInfo(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	char *RootPath = strchr(data,' ');
	if (RootPath == NULL)
		return 1;

	RootPath[0]=0;
	RootPath++;
	
	if ((RootPath[0] == '\\') && (RootPath[1] == '\\') && (RootPath[strlen(RootPath)-1] != '\\'))
		strcat(RootPath,"\\");

	char VName[256]; // Volume name
	DWORD SerialNum; // Serial Number
	DWORD MaxFileLen; // Maximum filename length
	DWORD FSFlags;	// File System Flags
	char FSName[256]; // File system type name (like FAT or NTFS)

	UINT ErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
		// So it doesn't say "Please insert disk A" or something

	if (!GetVolumeInformation(RootPath,
			VName,256,
			&SerialNum,
			&MaxFileLen,
			&FSFlags,
			FSName,
			256
		))
	{
		SetErrorMode(ErrMode);
		return 1;
	}
	if (!stricmp(data,"volname")) { strcpy(data,VName); return 3; }
	if (!stricmp(data,"serial")) { itoa(SerialNum,data,10); return 3; }
	if (!stricmp(data,"maxfilelen")) { itoa(MaxFileLen,data,10); return 3; }
	if (!stricmp(data,"fstype")) { strcpy(data,FSName); return 3; }
	if (!stricmp(data,"flags")) {
		data[0]=0;
#define FLAGINFO(cst,letter) if (FSFlags & cst) strcat(data,#letter)
		FLAGINFO(FS_PERSISTENT_ACLS,a);
		FLAGINFO(FS_CASE_IS_PRESERVED,c);
		FLAGINFO(FS_CASE_SENSITIVE,C);
		FLAGINFO(FILE_SUPPORTS_ENCRYPTION,e);
		FLAGINFO(FS_FILE_COMPRESSION,f);
		FLAGINFO(FILE_SUPPORTS_OBJECT_IDS,o);
		FLAGINFO(FILE_VOLUME_QUOTAS,q);
		FLAGINFO(FILE_SUPPORTS_REPARSE_POINTS,r);
		FLAGINFO(FILE_SUPPORTS_SPARSE_FILES,s);
		FLAGINFO(FS_UNICODE_STORED_ON_DISK,u);
		FLAGINFO(FS_VOL_IS_COMPRESSED,v);
#undef FLAGINFO
		return 3;
	}
	return 1;
}

int FAR PASCAL GetMemInfo(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	MEMORYSTATUS MemStat;

	GlobalMemoryStatus(&MemStat);

#define MEMINFO(str,memspot) if (!stricmp(data,#str)) { itoa(MemStat.memspot,data,10); return 3; }
	MEMINFO(memoryload,dwMemoryLoad);
	MEMINFO(totalphys,dwTotalPhys);
	MEMINFO(availphys,dwAvailPhys);
	MEMINFO(freephys,dwAvailPhys);
	MEMINFO(totalpagefile,dwTotalPageFile);
	MEMINFO(availpagefile,dwAvailPageFile);
	MEMINFO(freepagefile,dwAvailPageFile);
	MEMINFO(totalvirtual,dwTotalVirtual);
	MEMINFO(availvirtual,dwAvailVirtual);
	MEMINFO(freevirtual,dwAvailVirtual);
#undef MEMINFO
	return 1;
}

int FAR PASCAL GetSysMetrics(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	int Metric,Result;
#define GMETRIC(cst,str) if (!stricmp(data,#str)) Metric = cst
	GMETRIC(SM_ARRANGE,arrange);
	else GMETRIC(SM_CLEANBOOT,cleanboot);
	else GMETRIC(SM_CMONITORS,cmonitors);
	else GMETRIC(SM_CMOUSEBUTTONS,cmousebuttons);
	else GMETRIC(SM_CXBORDER,border.w);
	else GMETRIC(SM_CYBORDER,border.h);
	else GMETRIC(SM_CXCURSOR,cursor.w);
	else GMETRIC(SM_CYCURSOR,cursor.h);
	else GMETRIC(SM_CXDLGFRAME,dlgframe.w);
	else GMETRIC(SM_CYDLGFRAME,dlgframe.h);
	else GMETRIC(SM_CXDOUBLECLK,doubleclk.w);
	else GMETRIC(SM_CYDOUBLECLK,doubleclk.h);
	else GMETRIC(SM_CXDRAG,drag.w);
	else GMETRIC(SM_CYDRAG,drag.h);
	else GMETRIC(SM_CXEDGE,edge.w);
	else GMETRIC(SM_CYEDGE,edge.h);
	else GMETRIC(SM_CXFRAME,frame.w);
	else GMETRIC(SM_CYFRAME,frame.h);
	else GMETRIC(SM_CXFULLSCREEN,fullscreen.w);
	else GMETRIC(SM_CYFULLSCREEN,fullscreen.h);
	else GMETRIC(SM_CXHSCROLL,hscroll.w);
	else GMETRIC(SM_CYHSCROLL,hscroll.h);
	else GMETRIC(SM_CXHTHUMB,hthumb.w);
	else GMETRIC(SM_CXICON,icon.w);
	else GMETRIC(SM_CYICON,icon.h);
	else GMETRIC(SM_CXICONSPACING,iconspacing.w);
	else GMETRIC(SM_CYICONSPACING,iconspacing.h);
	else GMETRIC(SM_CXMAXIMIZED,maximized.w);
	else GMETRIC(SM_CYMAXIMIZED,maximized.h);
	else GMETRIC(SM_CXMAXTRACK,maxtrack.w);
	else GMETRIC(SM_CYMAXTRACK,maxtrack.h);
	else GMETRIC(SM_CXMENUCHECK,menucheck.w);
	else GMETRIC(SM_CYMENUCHECK,menucheck.h);
	else GMETRIC(SM_CXMENUSIZE,menusize.w);
	else GMETRIC(SM_CYMENUSIZE,menusize.h);
	else GMETRIC(SM_CXMIN,min.w);
	else GMETRIC(SM_CYMIN,min.h);
	else GMETRIC(SM_CXMINIMIZED,minimized.w);
	else GMETRIC(SM_CYMINIMIZED,minimized.h);
	else GMETRIC(SM_CXMINSPACING,minspacing.w);
	else GMETRIC(SM_CYMINSPACING,minspacing.h);
	else GMETRIC(SM_CXMINTRACK,mintrack.w);
	else GMETRIC(SM_CYMINTRACK,mintrack.h);
	else GMETRIC(SM_CXSCREEN,screen.w);
	else GMETRIC(SM_CYSCREEN,screen.h);
	else GMETRIC(SM_CXSIZE,size.w);
	else GMETRIC(SM_CYSIZE,size.h);
	else GMETRIC(SM_CXSIZEFRAME,sizeframe.w);
	else GMETRIC(SM_CYSIZEFRAME,sizeframe.h);
	else GMETRIC(SM_CXSMICON,smicon.w);
	else GMETRIC(SM_CYSMICON,smicon.h);
	else GMETRIC(SM_CXSMSIZE,smsize.w);
	else GMETRIC(SM_CYSMSIZE,smsize.h);
	else GMETRIC(SM_CXVIRTUALSCREEN,virtualscreen.w);
	else GMETRIC(SM_CYVIRTUALSCREEN,virtualscreen.h);
	else GMETRIC(SM_CXVSCROLL,vscroll.w);
	else GMETRIC(SM_CYVSCROLL,vscroll.h);
	else GMETRIC(SM_CYCAPTION,caption.h);
	else GMETRIC(SM_CYKANJIWINDOW,kanjiwindow.h);
	else GMETRIC(SM_CYMENU,menu.h);
	else GMETRIC(SM_CYSMCAPTION,smcaption.h);
	else GMETRIC(SM_CYVTHUMB,vthumb.h);
	else GMETRIC(SM_DBCSENABLED,dbcsenabled);
	else GMETRIC(SM_DEBUG,debug);
//	else GMETRIC(SM_IMMENABLED,immenabled);
	else GMETRIC(SM_MENUDROPALIGNMENT,menudropalignment);
	else GMETRIC(SM_MIDEASTENABLED,mideastenabled);
	else GMETRIC(SM_MOUSEPRESENT,mousepresent);
	else GMETRIC(SM_MOUSEWHEELPRESENT,mousewheelpresent);
	else GMETRIC(SM_NETWORK,network);
	else GMETRIC(SM_PENWINDOWS,penwindows);
//	else GMETRIC(SM_REMOTESESSION,remotesession);
	else GMETRIC(SM_SECURE,secure);
	else GMETRIC(SM_SAMEDISPLAYFORMAT,samedisplayformat);
	else GMETRIC(SM_SHOWSOUNDS,showsounds);
	else GMETRIC(SM_SLOWMACHINE,slowmachine);
	else GMETRIC(SM_SWAPBUTTON,swapbutton);
	else GMETRIC(SM_XVIRTUALSCREEN,virtualscreen.x);
	else GMETRIC(SM_YVIRTUALSCREEN,virtualscreen.y);
	else return 1;
#undef GMETRIC
	Result = GetSystemMetrics(Metric);
	switch(Metric)
	{
	case SM_ARRANGE:
		strcpy(data,(Result & ARW_STARTTOP ? "top " : "bottom "));
		strcat(data,(Result & ARW_STARTRIGHT ? "right " : "left "));
		strcat(data,(Result & ARW_UP ? "vertical" : "horizontal"));
		if (Result & ARW_HIDE)
			strcat(data," hide");
		break;
	case SM_CLEANBOOT:
		switch(Result)
		{
		case 0:
			strcpy(data,"normal");
			break;
		case 1:
			strcpy(data,"safe");
			break;
		case 2:
			strcpy(data,"netsafe");
			break;
		default:
			strcpy(data,"unknown");
			itoa(Result,data+7,10);
		}
		break;
	case SM_MENUDROPALIGNMENT:
		strcpy(data,(Result ? "right" : "left"));
		break;
	case SM_NETWORK:
		strcpy(data,(Result & 1 ? "$true" : "$false"));
		break;
	case SM_DBCSENABLED:
	case SM_DEBUG:
//	case SM_IMMENABLED:
	case SM_MIDEASTENABLED:
	case SM_MOUSEPRESENT:
	case SM_MOUSEWHEELPRESENT:
	case SM_PENWINDOWS:
//	case SM_REMOTESESSION:
	case SM_SECURE:
	case SM_SAMEDISPLAYFORMAT:
	case SM_SHOWSOUNDS:
	case SM_SLOWMACHINE:
	case SM_SWAPBUTTON:
		strcpy(data,(Result ? "$true" : "$false"));
		break;
	default:
		itoa(Result,data,10);
	}
	return 3;
}

int FAR PASCAL DLLInfo(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
	strcpy(data,AUTHINFO);
	return 3;
}

#ifdef __cplusplus
}
#endif
