Software Metering Example
Keywords: software metering
Question:
Does anyone have an example of using Winbatch for Software Metering?
Answer:
Here's an app to meter applications that are offerred from an NT Server. Enjoy!
;----------------------------------------------------------------------
; SECTION: PdcMeter
;
; Written by Brad Adkins
; badkins@ix.netcom.com
;
; Language: WIL - Windows Interface Language
; Compiler: WinBatch Compiler, Version 97D (2.4dbp)
;
; Setup:
;
; For each application to be metered, install PdcMeter in the application
; directory on your server. Configure PdcMeter support files for the
; application. Schedule the periodic "METER" task using your favorite
; scheduler, (AT probably won't cut it.)
;
; PdcMeter Support Files:
;
; Create Directories:
; appdir\License Permissions (RX)
; appdir\Log Permissions (RWX)
; appdir\Lock Permissions (RWXD)
; Create Files:
; appdir\pdcmeter.ini (see SAMPLE INI FILE below)
; appdir\License\license.dat one line text file, contains # of licenses
; appdir\License\current.dat one line text file, can be empty to start
; appdir\License\exception.dat one line text file, can be empty to start
; appdir\Log\license.log use "LOG_RESET" option to create this file
; appdir\Log\error.log use "LOG_RESET" option to create this file
;
; Description:
;
; Provides an application metering process. When executed with the "RUN"
; option will launch the target application, if the current license count
; is below the maximum threshold. The metering process is periodically
; executed using the "METER" option to update the current count and list
; of current users (every 10 minutes is adequate). This information is
; accessed by the "RUN" option. The "STATS" option will generate usage
; statistics. The "SERVICE" option will start the automatic "METER"
; mode. For the "SERVICE" option to work properly, it must be installed
; with the NT SRVANY utility first.
;
; Notes:
;
; The "SERVICE" capability is still in development and testing, so expect
; that you'll have to do some work here, but have fun if you choose to
; finish it. I currently use SmartBatch to schedule the "METER" task to
; run every 10 minutes for each application that is being metered.
;
; ErrorLevel:
; 0 = Success
; 1 = Initialization Error
; 2 = Param File Error
; 3 = File Locking Error
; 4 = License count exceeds maximum licenses allowed*
;
; *this can occur if someone executes the metered app without using
; pdcmeter to launch it
;
; Program Initialization Calling Sequence:
;
; Task 1 Task 2-7 Task 20-21
; --------------------- --------------------- ---------------------
; ReadParamApplication ReadParamApplication ReadParamService
; ReadParamClient ReadParamServer ReadParamNotification
; ReadParamNotification ReadParamNotification ParamDerived
; ReadDerived ParamDerived
;
;----------------------------------------------------------------------/
PNAME = "PdcMeter"
PVERSION = "Version 1.0 June 8, 1998"
COPYRIGHT = "Copyright 1998"
AUTHOR = "Brad Adkins, badkins@ix.netcom.com"
;----------------------------------------------------------------------
; SECTION: Global
;----------------------------------------------------------------------/
;string formatting constants
C1 = "%@CRLF%"
C2 = "%@CRLF%%@CRLF%"
;project version information
s = StrFill(" ", 5)
VERINFO = StrCat(s, PVERSION, "|", s, COPYRIGHT, @CRLF, s, AUTHOR)
;constants
APP_RUN = "APP_RUN"
APP_METER = "APP_METER"
APP_MOFF = "APP_MOFF"
LOG_RESET = "LOG_RESET"
LOG_OPEN = "LOG_OPEN"
LOG_CLOSE = "LOG_CLOSE"
LOG_STATS = "LOG_STATS"
LOG_SHOW = "LOG_SHOW"
SRV_START = "SRV_START"
SRV_STOP = "SRV_STOP"
LOCK_ATTEMPTS = 3
LOCK_DELAY = 0.5
;variables
LicenseLock = "A_Lock.lok"
LogLock = "B_Lock.lok"
ErrLock = "C_Lock.lok"
;----------------------------------------------------------------------
; SECTION: Environment
;----------------------------------------------------------------------/
WinHide("")
WinTitle("", PNAME)
TestMode = @FALSE
ProductionMode = @TRUE
;#12 - supress critical error dialog when being forceably shutdown
IntControl(12,5,0,0,0)
;#50 - no "go to web page" button on WIL critical error boxes
IntControl(50, 0, 0, 0, 0)
;#33 - listbox control allows only single items to be selected
IntControl(33, 0, 0, 0, 0)
;#1000 - application return code on exit using value in ErrorLevel
ErrorLevel = 0
;----------------------------------------------------------------------
; SECTION: Main
;----------------------------------------------------------------------/
gosub Initialize
select Task
case 1
;APP_RUN
gosub RunApp
break
case 2
;APP_METER
gosub MeterApp
break
case 3
;LOG_STATS
gosub RunStats
break
case 4
;LOG_SHOW
gosub ShowStats
break
case 5
;LOG_RESET
gosub CreateLogFiles
break
case 6
;LOG_OPEN
gosub LogOpen
break
case 7
;LOG_CLOSE
gosub LogClose
break
case 20
;SRV_START
gosub StartService
break
case 21
;SRV_STOP
gosub StopService
break
endselect
gosub ProgramExit
;----------------------------------------------------------------------
; SUBROUTINE: Initialize
;----------------------------------------------------------------------/
:Initialize
gosub IsWinNT
if Result
;Windows NT
OS = 2
else
;Windows 95
OS = 1
endif
Task = 1
if ProductionMode
HomeDir = DirHome()
else
HomeDir = "C:\Projects\wbt\PdcMeter\"
endif
IniFile = "%HomeDir%pdcmeter.ini"
if !FileExist(IniFile)
MsgTxt = "Program initialization file not found"
ErrorLevel = 1
gosub ErrorExit
endif
;holding down the shift key at startup reveals version information
keycheck=IsKeyDown(@SHIFT)
if keycheck == @YES
gosub DisplayVerInfo
gosub ProgramExit
endif
wildll = StrCat(HomeDir, "wbdbp32i.dll")
net95dll = StrCat(HomeDir, "www9532i.dll")
netntdll = StrCat(HomeDir, "wwwnt32i.dll")
inetdll = StrCat(HomeDir, "wwwsk32i.dll")
MsgTxt = "Required application file not found"
if ProductionMode
if !FileExist(wildll)
ErrorLevel = 1
gosub ErrorExit
endif
if !FileExist(net95dll)
ErrorLevel = 1
gosub ErrorExit
endif
if !FileExist(netntdll)
ErrorLevel = 1
gosub ErrorExit
endif
if !FileExist(inetdll)
ErrorLevel = 1
gosub ErrorExit
endif
endif
AddExtender(inetdll)
if OS == 1
AddExtender(net95dll)
UserName = StrLower(w95GetUser(@default))
endif
if OS == 2
AddExtender(netntdll)
UserName = StrLower(wNTGetUser(@default))
endif
ComputerName = RegQueryValue(@REGMACHINE,"System\CurrentControlSet\control\ComputerName\ComputerName[ComputerName]")
;process the command line
if Param0 > 1
MsgTxt = "Invalid command line"
ErrorLevel = 1
gosub ErrorExit
endif
if Param0 == 0
Param0 = 1
Param1 = "APP_RUN"
endif
goodparam = @FALSE
if Param1 == APP_RUN
goodparam = @TRUE
Task = 1
endif
if Param1 == APP_METER
goodparam = @TRUE
Task = 2
endif
if Param1 == LOG_STATS
goodparam = @TRUE
Task = 3
endif
if Param1 == LOG_SHOW
goodparam = @TRUE
Task = 4
endif
if Param1 == LOG_RESET
goodparam = @TRUE
Task = 5
endif
if Param1 == LOG_OPEN
goodparam = @TRUE
Task = 6
endif
if Param1 == LOG_CLOSE
goodparam = @TRUE
Task = 7
endif
if Param1 == SRV_START
goodparam = @TRUE
Task = 20
endif
if Param1 == SRV_STOP
goodparam = @TRUE
Task = 21
endif
AppParm = ""
if !goodparam
;assume thing passed is a filname
;this will override the value in the ini file if one is given there
AppParm = Param1
endif
if Task > 1
if OS <> 2
MsgTxt = "Requested task only runs under Windows NT"
ErrorLevel = 1
gosub ErrorExit
endif
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: StartService
;----------------------------------------------------------------------/
:StartService
;start metering and loop forever or until service stop request is received
;when installed as a service, the service stop request will unload this app
;based on the window title which is modified below for uniqueness
;read pdcmeter.ini file
gosub ReadParamService
gosub ParamDerived
wtitle = "%PNAME%Service"
if WinExist(wtitle)
ErrorLevel = 2
MsgTxt = "Service is already started"
goto ErrorExit
endif
WinTitle("", wtitle)
;must write to each application log file!!!
a =StrFix(SRV_START, " ", 9)
LogTxt = "%a%|%AppName%"
gosub WriteLogFile
if OpenLogOnStart
;must write to each application log file!!!
gosub LogOpen
endif
while @TRUE
;meter all configured applications on each pass
;mechanism provided to return here if ErrorExit is called by any one application
;is it metering time
p1 = MeterFrom
p2 = MeterTo
gosub QualifyTime
if result
;meter away
for meterc = 1 to MeterCount
ErrorLevel = 0
;open application metering definition file
IniFile = ItemExtract(meterc, ApplicationList, "|")
gosub ParamSetup
gosub ReadParamApplication
gosub ReadParamServer
gosub ParamFinish
Yield()
;perform metering
if ErrorLevel == 0
gosub MeterApp
endif
Yield()
next
else
;probably don't want to to this!!!
a =StrFix(APP_MOFF, " ", 9)
LogTxt = "%a%|%AppName%"
gosub WriteLogFile
endif
;wait
TimeDelay(MeterInterval)
endwhile
ErrorLevel = 0
return
;----------------------------------------------------------------------
; SUBROUTINE: StopService
;----------------------------------------------------------------------/
:StopService
;read pdcmeter.ini file
gosub ReadParamService
gosub ParamDerived
result = @FALSE
wtitle = "%PNAME%Service"
if WinExist(wtitle)
IntControl(47, wtitle, 0, 0, 0)
result = @TRUE
a =StrFix(SRV_STOP, " ", 9)
;probably want to do this to all logs!!!
LogTxt = "%a%|%AppName%"
gosub WriteLogFile
if CloseLogOnStop
;probably want to do this to all logs!!!
gosub LogClose
endif
endif
if !result
ErrorLevel = 2
MsgTxt = "Unable to stop Service"
gosub ErrorExit
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: RunApp
;----------------------------------------------------------------------/
:RunApp
; step 1 - get license count (maximum users)
; step 2 - get count of current users
; step 3 - run or abort based on count
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamClient
gosub ReadParamNotification
gosub ParamDerived
gosub ReadLicenseData
if CurrentCount < MaxCount
a =StrFix(APP_RUN, " ", 9)
LogTxt = "%a%|%AppName%|username=%UserName%"
gosub WriteLogFile
LastError()
ErrorMode(@OFF)
Run(AppFileName, AppParm)
ErrorMode(@CANCEL)
return
endif
;we are at or over the limit
if CurrentCount == MaxCount
MsgTxt = "Maximum number of licenses is currently in use for|%AppName%|Please try again later or contact your System Administrator"
gosub DisplayMessage
return
endif
if CurrentCount > MaxCount
MsgTxt = "Maximum number of licenses has been exceeded for|%AppName%|Please contact your System Administrator"
ErrorLevel = 4
gosub ErrorExit
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: MeterApp
;----------------------------------------------------------------------/
:MeterApp
;NET FILE sample output
;---------+---------+---------+---------+---------+---------+---------+----
;833931 C:\NTRESKIT\WINSCL.EXE ADKINSB 0
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
;step 1 - read current license info to get MaxCount and ExceptionList
gosub ReadLicenseData
;step 2 - run NET FILE command and write output to license directory
RunWait("cmd.exe", "/c net file > %LicenseDirectory%netfile.txt")
;step 3 - parse netfile output looking for CheckString
CurrentCount = 0
UserList = ""
hf = FileOpen("%LicenseDirectory%netfile.txt", "READ")
while @TRUE
s = FileRead(hf)
if s == "*EOF*" then break
p = StrIndexNc(s, CheckString, 1, @FWDSCAN)
if p > 0
CurrentCount = CurrentCount + 1
UserList = StrCat(UserList, StrTrim(StrSub(s, 52, 20)), "|")
endif
endwhile
FileClose(hf)
;step 4 - parse log in binary buffer rebuilding the user exception list
gosub ReadLogFile
;for each name in UserList (netfile)
;if name is not in the buffer (license log contents)
;we have a user that has not used the wrapper to launch the app
ic = ItemCount(UserList, "|")
for i = 1 to ic
ulname = StrCat("username=", StrLower(ItemExtract(i, UserList, "|")))
;Message("", ulname)
if BinaryIndexNc(binbuf, 1, ulname, @FWDSCAN) == 0
;bingo name from netfile is not in the license log
ulname = StrReplace(ulname, "username=", "")
ExceptionList = StrCat(ExceptionList, ulname, "|")
endif
next
BinaryFree(binbuf)
;step 5 - write current user count & current user list
gosub WriteLicenseData
;step 6 - append a metering record to Log File
a =StrFix(APP_METER, " ", 9)
LogTxt = "%a%|%AppName%|%CurrentCount%|%MaxCount%"
gosub WriteLogFile
return
;----------------------------------------------------------------------
; SUBROUTINE: RunStats
;----------------------------------------------------------------------/
:RunStats
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
Output = "FILE"
gosub SetupLogFiles
;compile summary information
gosub BuildSummary
if SendStats
thelog = SummaryLog
gosub SendReport
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: ShowStats
;----------------------------------------------------------------------/
:ShowStats
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
Output = "TEMP"
gosub SetupLogFiles
;compile summary information
gosub BuildSummary
Run("notepad.exe", TmpSum)
if SendShow
thelog = TmpSum
gosub SendReport
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: CreateLogFiles
;----------------------------------------------------------------------/
:CreateLogFiles
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
a =StrFix(LOG_RESET, " ", 9)
header = StrCat(TimeYmdHms(), "|%a%|%AppName%")
hf = FileOpen(LogFile, "WRITE")
FileWrite(hf, header)
FileClose(hf)
hf = FileOpen(ErrorLog, "WRITE")
FileWrite(hf, header)
FileClose(hf)
hf = FileOpen(CurrentDataFile, "WRITE")
FileWrite(hf, header)
FileWrite(hf, "0")
FileWrite(hf, "")
FileClose(hf)
hf = FileOpen(ExceptionDataFile, "WRITE")
FileWrite(hf, header)
FileWrite(hf, "")
FileClose(hf)
Drop(header)
return
;----------------------------------------------------------------------
; SUBROUTINE: LogOpen
;----------------------------------------------------------------------/
:LogOpen
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
a =StrFix(LOG_OPEN, " ", 9)
LogTxt = "%a%|%AppName%"
gosub WriteLogFile
ErrTxt = "%a%|%AppName%"
gosub WriteErrorFile
return
;----------------------------------------------------------------------
; SUBROUTINE: LogClose
;----------------------------------------------------------------------/
:LogClose
;read pdcmeter.ini file
gosub ReadParamApplication
gosub ReadParamServer
gosub ReadParamNotification
gosub ParamDerived
a =StrFix(LOG_CLOSE, " ", 9)
LogTxt = "%a%|%AppName%"
gosub WriteLogFile
ErrTxt = "%a%|%AppName%"
gosub WriteErrorFile
return
;----------------------------------------------------------------------
; SUBROUTINE: WriteLicenseData
;----------------------------------------------------------------------/
:WriteLicenseData
if StrSub(UserList, StrLen(UserList), 1) == "|"
UserList = StrSub(UserList, 1, StrLen(UserList) - 1)
endif
if StrSub(ExceptionList, StrLen(ExceptionList), 1) == "|"
ExceptionList = StrSub(ExceptionList, 1, StrLen(ExceptionList) - 1)
endif
a =StrFix(LOG_RESET, " ", 9)
header = StrCat(TimeYmdHms(), "|%a%|%AppName%")
;lock the license files
LockFile = LicenseLockFile
gosub LockFiles
hf = FileOpen(CurrentDataFile, "WRITE")
FileWrite(hf, header)
FileWrite(hf, CurrentCount)
FileWrite(hf, UserList)
FileClose(hf)
hf = FileOpen(ExceptionDataFile, "WRITE")
FileWrite(hf, header)
FileWrite(hf, ExceptionList)
FileClose(hf)
;unlock the license files
gosub UnLockFiles
Drop(header)
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadLicenseData
;----------------------------------------------------------------------/
:ReadLicenseData
;lock the license files
LockFile = LicenseLockFile
gosub LockFiles
;read maximum user count
hf = FileOpen(LicenseDataFile, "READ")
MaxCount = FileRead(hf)
FileClose(hf)
;read current data
hf = FileOpen(CurrentDataFile, "READ")
header = FileRead(hf)
CurrentCount = FileRead(hf)
UserList = FileRead(hf)
FileClose(hf)
;read exception list
hf = FileOpen(ExceptionDataFile, "READ")
header = FileRead(hf)
ExceptionList = FileRead(hf)
FileClose(hf)
;unlock the license files
gosub UnLockFiles
Drop(header)
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadLogFile
;----------------------------------------------------------------------/
:ReadLogFile
;lock the log files
LockFile = LogLockFile
gosub LockFiles
;read log file into a binary buffer
fs = FileSize(LogFile)
binbuf = BinaryAlloc(fs)
if binbuf == 0
MsgTxt = "Critical Error: BinaryAlloc Failed"
ErrorLevel = 2
gosub ErrorExit
else
;read the file into the buffer
BinaryRead(binbuf, LogFile)
endif
;unlock the log files
gosub UnLockFiles
return
;----------------------------------------------------------------------
; SUBROUTINE: WriteLogFile
;----------------------------------------------------------------------/
:WriteLogFile
;lock the log files
LockFile = LogLockFile
gosub LockFiles
hf = FileOpen(LogFile, "APPEND")
FileWrite(hf, StrCat(TimeYmdHms(), "|", LogTxt))
FileClose(hf)
;unlock the log files
gosub UnLockFiles
return
;----------------------------------------------------------------------
; SUBROUTINE: WriteErrorFile
;----------------------------------------------------------------------/
:WriteErrorFile
;do not call LockFiles or loop might occur
LockFile = ErrLockFile
i = 0
while @TRUE
if FileExist(LockFile)
TimeDelay(LOCK_DELAY)
i = i + 1
if i > LOCK_ATTEMPTS
;unable to get a lock, out of luck
;this should never happen :-)
if Task > 19 then return
exit
endif
else
break
endif
endwhile
;create the requested lock file
hf = FileOpen(LockFile, "WRITE")
FileWrite(hf, "LOCKED")
FileClose(hf)
;write to the error log
hf = FileOpen(ErrorLog, "APPEND")
FileWrite(hf, StrCat(TimeYmdHms(), "|", ErrTxt))
FileClose(hf)
;unlock the error log
gosub UnLockFiles
return
;----------------------------------------------------------------------
; SUBROUTINE: SetupLogFiles
;----------------------------------------------------------------------/
:SetupLogFiles
;lock the log file
LockFile = LogLockFile
gosub LockFiles
;rename the log file and error log in preparation for statistical processing
if Output == "FILE"
FileRename(LogFile, BackupLog)
FileRename(ErrorLog, BackupErr)
gosub CreateLogFiles
endif
if Output == "TEMP"
if FileExist(TmpLog) then FileDelete(TmpLog)
FileCopy(LogFile, TmpLog, @FALSE)
if FileExist(TmpErr) then FileDelete(TmpErr)
FileCopy(ErrorLog, TmpErr, @FALSE)
endif
;unlock the log file
gosub UnLockFiles
return
;----------------------------------------------------------------------
; SUBROUTINE: BuildSummary
;----------------------------------------------------------------------/
:BuildSummary
;first load up the current licensing information
gosub ReadLicenseData
;get current service status
LastError()
ErrorMode(@OFF)
cstate = wntSvcStatus("", "PdcMeter", 0, 2)
ErrorMode(@CANCEL)
if LastError() == 0
switch cstate
case 1
currentstate = "SERVICE_STOPPED"
break
case 2
currentstate = "SERVICE_START_PENDING"
break
case 3
currentstate = "SERVICE_STOP PENDING"
break
case 4
currentstate = "SERVICE_RUNNING"
break
case 5
currentstate = "SERVICE_CONTINUE_PENDING"
break
case 6
currentstate = "SERVICE_PAUSE_PENDING"
break
case 7
currentstate = "SERVICE_PAUSED"
break
endswitch
else
currentstate = "SERVICE_NOT_INSTALLED"
endif
ms = ""
me = ""
md = ""
ma = ""
mc = 0
ec = 0
ul = ""
ilm = 0
iem = 0
igm = 0
if Output == "FILE"
fn_log = BackupLog
fn_err = BackupErr
fn_sum = SummaryLog
endif
if Output == "TEMP"
fn_log = TmpLog
fn_err = TmpErr
fn_sum = TmpSum
endif
hf = FileOpen(fn_log, "READ")
s = FileRead(hf)
ms = StrSub(s, 1, 19)
FileClose(hf)
ReadingLog = @FALSE
hf = FileOpen(fn_log, "READ")
while @TRUE
s = FileRead(hf)
if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
if s == "*EOF*" then break
if ReadingLog
me = StrSub(s, 1, 19)
;process this line
if StrIndex(s, "|%APP_METER%", 1, @FWDSCAN) > 0
mc = mc + 1
icc = ItemExtract(4, s, "|")
if icc < MaxCount then ilm = ilm + 1
if icc == MaxCount then iem = iem + 1
if icc > MaxCount then igm =igm + 1
endif
if StrIndex(s, "|%APP_RUN%", 1, @FWDSCAN) > 0
ec = ec + 1
un = ItemExtract(4, s, "|")
un = StrReplace(un, "username=", "")
if StrIndex(ul, un, 1, @FWDSCAN) < 1
ul = StrCat(ul, un, "|")
endif
endif
endif
endwhile
FileClose(hf)
md = TimeDiffSecs(me, ms)
p1 = md
p2 = mc
gosub TimeDiffFormat
md = retval1
ma = retval2
uc = ItemCount(ul, "|")
;setup notification temporary varibles
nof = "OFF"
nom = "NO"
nop = "NO"
noe = "NO"
if Notification then nof = "ON"
if SendEmail then nom = "YES"
if SendPage then nop = "YES"
if EventLog then noe = "YES"
ExceptionCount = ItemCount(ExceptionList, "|")
hf = FileOpen(fn_sum, "WRITE")
FileWrite(hf, "")
FileWrite(hf, "PDCMETER")
FileWrite(hf, StrCat(StrFix(" REPORT DATE", " ", 22), "= ", TimeYmdHms()))
FileWrite(hf, StrCat(StrFix(" GENERATED BY", " ", 22), "= ", ComputerName, " ", UserName))
FileWrite(hf, "")
FileWrite(hf, "APPLICATION")
FileWrite(hf, StrCat(StrFix(" NAME", " ", 22), "= %AppName%"))
FileWrite(hf, StrCat(StrFix(" LICENSES", " ", 22), "= %MaxCount%"))
FileWrite(hf, StrCat(StrFix(" FILE", " ", 22), "= ", StrLower(AppFile)))
FileWrite(hf, StrCat(StrFix(" PARAMETERS", " ", 22), "= %AppParm%"))
FileWrite(hf, "")
FileWrite(hf, "NOTIFICATION")
FileWrite(hf, StrCat(StrFix(" CURRENT STATE", " ", 22), "= %nof%"))
FileWrite(hf, StrCat(StrFix(" EVENT LOG", " ", 22), "= %noe%"))
FileWrite(hf, StrCat(StrFix(" PAGER", " ", 22), "= %nop%"))
FileWrite(hf, StrCat(StrFix(" EMAIL", " ", 22), "= %nom%"))
FileWrite(hf, "")
FileWrite(hf, "CURRENT INTERVAL")
FileWrite(hf, StrCat(StrFix(" USERS", " ", 22), "= %CurrentCount%"))
j = ItemCount(UserList, "|")
for i = 1 to j
FileWrite(hf, StrCat(" ===> ", ItemExtract(i, UserList, "|")))
next
FileWrite(hf, "")
FileWrite(hf, "METERING")
FileWrite(hf, StrCat(StrFix(" START", " ", 22), "= %ms%"))
FileWrite(hf, StrCat(StrFix(" LAST", " ", 22), "= %me%"))
FileWrite(hf, StrCat(StrFix(" ELAPSED", " ", 22), "= %md%"))
FileWrite(hf, StrCat(StrFix(" INTERVAL (AVG)", " ", 22), "= %ma%"))
FileWrite(hf, StrCat(StrFix(" NUMBER OF INTERVALS", " ", 22), "= %mc%"))
FileWrite(hf, StrCat(StrFix(" INTERVALS LT MAX LC", " ", 22), "= %ilm%"))
FileWrite(hf, StrCat(StrFix(" INTERVALS EQ MAX LC", " ", 22), "= %iem%"))
FileWrite(hf, StrCat(StrFix(" INTERVALS GT MAX LC", " ", 22), "= %igm%"))
FileWrite(hf, StrCat(StrFix(" INVOCATIONS", " ", 22), "= %ec%"))
FileWrite(hf, StrCat(StrFix(" LICENSE EXCEPTIONS", " ", 22), "= %ExceptionCount%"))
for i = 1 to ExceptionCount
FileWrite(hf, StrCat(" ===> ", ItemExtract(i, ExceptionList, "|")))
next
FileWrite(hf, StrCat(StrFix(" UNIQUE USER COUNT", " ", 22), "= %uc%"))
for i = 1 to uc
FileWrite(hf, StrCat(" ===> ", ItemExtract(i, ul, "|")))
next
FileWrite(hf, "")
FileWrite(hf, "SERVICE")
FileWrite(hf, StrCat(StrFix(" SERVICE NAME", " ", 22), "= PdcMeter"))
FileWrite(hf, StrCat(StrFix(" CURRENT STATE", " ", 22), "= %currentstate%"))
FileWrite(hf, StrCat(StrFix(" METER INTERVAL", " ", 22), "= <-registry"))
FileWrite(hf, StrCat(StrFix(" METER FROM", " ", 22), "= <-registry"))
FileWrite(hf, StrCat(StrFix(" METER TO", " ", 22), "= <-registry"))
FileWrite(hf, StrCat(StrFix(" APPLICATIONS", " ", 22), "= <-registry"))
;for i = 1 to al
; FileWrite(hf, StrCat(" ===> ", ItemExtract(i, al, "|")))
;next
FileWrite(hf, "")
FileWrite(hf, "ERROR LOG")
FileWrite(hf, " RESPONSE=0 (WAITING RESPONSE)")
ReadingLog = @FALSE
hf2 = FileOpen(fn_err, "READ")
while @TRUE
s = FileRead(hf2)
if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
if s == "*EOF*" then break
if StrIndex(s, "RESPONSE=0", 1, @FWDSCAN) > 0
FileWrite(hf, StrCat(" ===> ", s))
endif
endwhile
FileClose(hf2)
FileWrite(hf, "")
FileWrite(hf, "ERROR LOG")
FileWrite(hf, " RESPONSE=1 (RESPONDED)")
ReadingLog = @FALSE
hf2 = FileOpen(fn_err, "READ")
while @TRUE
s = FileRead(hf2)
if StrIndex(s, LOG_OPEN, 1, @FWDSCAN) > 0 then ReadingLog = @TRUE
if StrIndex(s, LOG_CLOSE, 1, @FWDSCAN) > 0 then s = "*EOF*"
if s == "*EOF*" then break
if StrIndex(s, "RESPONSE=1", 1, @FWDSCAN) > 0
FileWrite(hf, StrCat(" ===> ", s))
endif
endwhile
FileWrite(hf, "")
FileClose(hf2)
FileClose(hf)
;this is ug-ly
Drop(nof, nom, noe, nop, ul, uc, ec, mc, md, ma, me, ms, fn_log, fn_err, fn_sum, ilm, iem, igm, retval1, retval2)
return
;----------------------------------------------------------------------
; SUBROUTINE: LockFiles
;----------------------------------------------------------------------/
:LockFiles
;see if somebody else has a lock already
i = 0
while @TRUE
if FileExist(LockFile)
TimeDelay(LOCK_DELAY)
i = i + 1
if i > LOCK_ATTEMPTS
;unable to grab a lock
MsgTxt = "Unable to obtain file lock|Please contact your System Administrator"
ErrorLevel = 3
gosub ErrorExit
endif
else
break
endif
endwhile
;create the requested lock file
hf = FileOpen(LockFile, "WRITE")
FileWrite(hf, "LOCKED")
FileClose(hf)
return
;----------------------------------------------------------------------
; SUBROUTINE: UnLockFiles
;----------------------------------------------------------------------/
:UnLockFiles
if FileExist(LockFile) then FileDelete(LockFile)
return
;----------------------------------------------------------------------
; SUBROUTINE: ParamSetup
;----------------------------------------------------------------------/
:ParamSetup
e1 = "Entry invalid"
e2 = "Directory not found"
e3 = "File not found"
e4 = "Notification entry invalid"
e5 = "Service entry invalid"
return
;----------------------------------------------------------------------
; SUBROUTINE: ParamClean
;----------------------------------------------------------------------/
:ParamClean
Drop(en, e1, e2, e3, e4, en)
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamApplication
;----------------------------------------------------------------------/
:ReadParamApplication
gosub ParamSetup
Section = "Application"
AppName = IniReadPvt(Section, "AppName", "", IniFile)
AppFile = IniReadPvt(Section, "AppFile", "", IniFile)
if StrLen(AppParm) < 1
AppParm = IniReadPvt(Section, "AppParm", "", IniFile)
endif
en = 0
if StrLen(AppName) < 1 then en = en + 1
if StrLen(AppFile) < 1 then en = en + 1
if en > 0
ErrorLevel = 2
MsgTxt = "Error %en% - %e1%"
gosub ErrorExit
endif
gosub ParamClean
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamClient
;----------------------------------------------------------------------/
:ReadParamClient
gosub ParamSetup
Section = "Run"
AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
gosub ParamValidateDf
gosub ParamClean
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamServer
;----------------------------------------------------------------------/
:ReadParamServer
gosub ParamSetup
Section = "Meter"
AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
LogEventPath = IniReadPvt(Section, "LogEventPath", "", IniFile)
gosub ParamValidateLe
gosub ParamValidateDf
gosub ParamClean
return
;----------------------------------------------------------------------
; SUBROUTINE: ParamValidateLe
;----------------------------------------------------------------------/
:ParamValidateLe
;validate logevent path
if StrSub(StrLen(LogEventPath), 1, 1) <> "\"
LogEventPath = "%LogEventPath%\"
endif
LogEventPath = StrUpper(StrCat(LogEventPath, "logevent.exe"))
if !FileExist(LogEventPath)
ErrorLevel = 2
MsgTxt = "File not found|%LogEventPath%"
gosub ErrorExit
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: ParamValidateDf
;----------------------------------------------------------------------/
:ParamValidateDf
;validate required entries have been made
en = 16
if StrLen(AppPath) < 1 then en = en + 1
if StrLen(LicensePath) < 1 then en = en + 1
if en > 16
ErrorLevel = 2
MsgTxt = "Error %en% - %e1%"
gosub ErrorExit
endif
;fix-up path strings
if StrSub(StrLen(AppPath), 1, 1) <> "\"
AppPath = "%AppPath%\"
endif
if StrSub(StrLen(LicensePath), 1, 1) <> "\"
LicensePath = "%LicensePath%\"
endif
;set derived values
AppFileName = StrUpper(StrCat(AppPath, AppFile))
CheckString = AppFile
LogDirectory = StrUpper(StrCat(LicensePath, "log\"))
LockDirectory = StrUpper(StrCat(LicensePath, "lock\"))
LicenseDirectory = StrUpper(StrCat(LicensePath, "license\"))
LicenseDataFile = StrUpper(StrCat(LicenseDirectory, "license.dat"))
CurrentDataFile = StrUpper(StrCat(LicenseDirectory, "current.dat"))
ExceptionDataFile = StrUpper(StrCat(LicenseDirectory, "exception.dat"))
LogFile = StrUpper(StrCat(LogDirectory, "license.log"))
ErrorLog = StrUpper(StrCat(LogDirectory, "error.log"))
;check directories
en = 32
if !DirExist(LogDirectory) then en = en + 1
if !DirExist(LockDirectory) then en = en + 1
if !DirExist(LicenseDirectory) then en = en + 1
if en > 32
ErrorLevel = 2
MsgTxt = "Error %en% - %e2%"
gosub ErrorExit
endif
;check files
en = 48
if !FileExist(AppFileName) then en = en + 1
if !FileExist(LicenseDataFile) then en = en + 1
if !FileExist(CurrentDataFile) then en = en + 1
if !FileExist(ExceptionDataFile) then en = en + 1
if !FileExist(LogFile) then en = en + 1
if !FileExist(ErrorLog) then en = en + 1
if en > 48
ErrorLevel = 2
MsgTxt = "Error %en% - %e3%"
gosub ErrorExit
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamNotification
;----------------------------------------------------------------------/
:ReadParamNotification
gosub ParamSetup
Section = "Notification"
Notification = IniReadPvt(Section, "Notification", "", IniFile)
EventLog = IniReadPvt(Section, "EventLog", "", IniFile)
AlertList = IniReadPvt(Section, "AlertList", "", IniFile)
FromAddress = IniReadPvt(Section, "FromAddress", "", IniFile)
ReportAddress = IniReadPvt(Section, "ReportAddress", "", IniFile)
PagerKeyList = IniReadPvt(Section, "PagerKeyList", "", IniFile)
NotificationText = IniReadPvt(Section, "NotificationText", "", IniFile)
MailServer = IniReadPvt(Section, "MailServer", "", IniFile)
PagingAddress = IniReadPvt(Section, "PagingAddress", "", IniFile)
SendEmail = IniReadPvt(Section, "SendEmail", "", IniFile)
SendPage = IniReadPvt(Section, "SendPage", "", IniFile)
SendShow = IniReadPvt(Section, "SendShow", "", IniFile)
SendStats = IniReadPvt(Section, "SendStats", "", IniFile)
;validate required entries have been made
en = 64
if StrLen(Notification) < 1 then en = en + 1
if StrLen(EventLog) < 1 then en = en + 1
if StrLen(AlertList) < 1 then en = en + 1
if StrLen(FromAddress) < 1 then en = en + 1
if StrLen(ReportAddress) < 1 then en = en + 1
if StrLen(PagerKeyList) < 1 then en = en + 1
if StrLen(NotificationText) < 1 then en = en + 1
if StrLen(MailServer) < 1 then en = en + 1
if StrLen(PagingAddress) < 1 then en = en + 1
if StrLen(SendEmail) < 1 then en = en + 1
if StrLen(SendPage) < 1 then en = en + 1
if StrLen(SendShow) < 1 then en = en + 1
if StrLen(SendStats) < 1 then en = en + 1
if en > 64
ErrorLevel = 2
MsgTxt = "Error %en% - %e4%"
gosub ErrorExit
endif
en = 80
if (Notification == "YES") || (Notification == "NO")
if Notification == "YES"
Notification = @TRUE
else
Notification = @FALSE
endif
else
en = en + 1
endif
if (EventLog == "YES") || (EventLog == "NO")
if EventLog == "YES"
EventLog = @TRUE
else
EventLog = @FALSE
endif
else
en = en + 1
endif
if (SendEmail == "YES") || (SendEmail == "NO")
if SendEmail == "YES"
SendEmail = @TRUE
else
SendEmail = @FALSE
endif
else
en = en + 1
endif
if (SendPage == "YES") || (SendPage == "NO")
if SendPage == "YES"
SendPage = @TRUE
else
SendPage = @FALSE
endif
else
en = en + 1
endif
if (SendShow == "YES") || (SendShow == "NO")
if SendShow == "YES"
SendShow = @TRUE
else
SendShow = @FALSE
endif
else
en = en + 1
endif
if (SendStats == "YES") || (SendStats == "NO")
if SendStats == "YES"
SendStats = @TRUE
else
SendStats = @FALSE
endif
else
en = en + 1
endif
if en > 80
ErrorLevel = 2
MsgTxt = "Error %en% - %e4%"
gosub ErrorExit
endif
;list counts must be identical
alc = ItemCount(AlertList, "|")
klc = ItemCount(PagerKeyList, "|")
if alc <> klc
ErrorLevel = 2
MsgTxt = "Error 97 %e4%|List counts are invalid"
gosub ErrorExit
endif
Drop(alc, klc)
gosub ParamClean
return
;----------------------------------------------------------------------
; SUBROUTINE: ReadParamService
;----------------------------------------------------------------------/
:ReadParamService
gosub ParamSetup
Section = "Service"
AppName = "PdcMeter Service"
AppFile = ""
AppParm = ""
AppPath = IniReadPvt(Section, "AppPath", "", IniFile)
LicensePath = IniReadPvt(Section, "LicensePath", "", IniFile)
LogEventPath = IniReadPvt(Section, "LogEventPath", "", IniFile)
gosub ParamValidateLe
gosub ParamValidateDf
MeterInterval = IniReadPvt(Section, "MeterInterval", "", IniFile)
MeterFrom = IniReadPvt(Section, "MeterFrom", "", IniFile)
MeterTo = IniReadPvt(Section, "MeterTo", "", IniFile)
OpenLogOnStart = IniReadPvt(Section, "OpenLogOnStart", "", IniFile)
CloseLogOnStop = IniReadPvt(Section, "CloseLogOnStop", "", IniFile)
en = 112
if !IsNumber(MeterInterval)
en = en + 1
MsgTxt = "Error %en% - %e5%"
ErrorLevel = 2
gosub ErrorExit
endif
ct1 = MeterFrom
ct2 = MeterTo
gosub CheckTime
if !result
en = en + 1
MsgTxt = "Error %en% - %e5%"
ErrorLevel = 2
gosub ErrorExit
endif
en = 128
if (OpenLogOnStart == "YES") || (OpenLogOnStart == "NO")
if OpenLogOnStart == "YES"
OpenLogOnStart = @TRUE
else
OpenLogOnStart = @FALSE
endif
else
en = en + 1
endif
if (CloseLogOnStop == "YES") || (CloseLogOnStop == "NO")
if CloseLogOnStop == "YES"
CloseLogOnStop = @TRUE
else
CloseLogOnStop = @FALSE
endif
else
en = en + 1
endif
if en > 128
ErrorLevel = 2
MsgTxt = "Error %en% - %e5%"
gosub ErrorExit
endif
;read the ApplicationList and set the MeterCount
en = 144
MeterCount = 0
ApplicationList = ""
i = 1
while @TRUE
a = IniReadPvt(Section, "Application%i%", "", IniFile)
if StrLen(a) > 0
MeterCount = MeterCount + 1
ApplicationList = StrCat(ApplicationList, a, "|")
else
break
endif
i = i + 1
endwhile
if MeterCount < 1
en = en + 1
MsgTxt = "Error %en% - %e5%"
ErrorLevel = 2
gosub ErrorExit
endif
gosub ParamClean
return
;----------------------------------------------------------------------
; SUBROUTINE: ParamDerived
;----------------------------------------------------------------------/
:ParamDerived
LicenseLockFile = StrCat(LockDirectory, LicenseLock)
LogLockFile = StrCat(LockDirectory, LogLock)
ErrLockFile = StrCat(LockDirectory, ErrLock)
gosub GetTimeFn
BackupLog = StrCat(LogDirectory, "Reports\_", TimeFn, "_LOG_BAK.txt")
BackupErr = StrCat(LogDirectory, "Reports\_", TimeFn, "_ERR_BAK.txt")
SummaryLog = StrCat(LogDirectory, "Reports\_", TimeFn, "_REPORT.txt")
TmpLog = StrCat(LogDirectory, "Reports\_PDCMETER_LOG_TMP.txt")
TmpErr = StrCat(LogDirectory, "Reports\_PDCMETER_ERR_TMP.txt")
TmpSum = StrCat(LogDirectory, "Reports\_PDCMETER_CUR_TMP.txt")
if !DirExist(StrCat(LogDirectory, "Reports"))
DirMake(StrCat(LogDirectory, "Reports"))
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: IsWinNT
;----------------------------------------------------------------------/
:IsWinNT
Result = @TRUE
platform=WinMetrics(-4)
if platform <> 4
Result = @FALSE
endif
Drop(platform)
return
;----------------------------------------------------------------------
; SUBROUTINE: CheckTime
;----------------------------------------------------------------------/
:CheckTime
result = @FALSE
i = 1
while IsDefined(ct%i%)
if StrLen(ct%i%) <> 5 then return
if StrSub(ct%i%, 3, 1) <> ":" then return
s1 = StrSub(ct%i%, 1, 2)
s2 = StrSub(ct%i%, 4, 2)
StrReplace(s1, "0", "")
StrReplace(s2, "0", "")
if !IsNumber(s1) then return
if !IsNumber(s2) then return
if s1 > 23 then return
if s2 > 59 then return
i = i + 1
endwhile
j = i - 1
result = @TRUE
;cleanup
for i = 1 to j
Drop(ct%i%)
next
Drop(i, j, s1, s2)
return
;----------------------------------------------------------------------
; SUBROUTINE: QualifyTime
;----------------------------------------------------------------------/
:QualifyTime
;assumes valid from-time in p1, to-time in p2, and current-time in p3
;valid format is 00:00 (midnight) to 23:59
;time window cannot span midnight
result = @FALSE
p3 = StrSub(TimeYmdHms(), 12, 5)
p3 = StrReplace(p3, ":", "")
p2 = StrReplace(p2, ":", "")
p1 = StrReplace(p1, ":", "")
if (p1 < p3) && (p3 < p2) then result = @TRUE
;a = StrCat(" p1(from)=", p1, " p2(to)=", p2, " p3(current)= ", p3)
;LogTxt = a
;gosub WriteLogFile
return
;----------------------------------------------------------------------
; SUBROUTINE: GetTimeFn
;----------------------------------------------------------------------/
:GetTimeFn
TimeFn = TimeYmdHms()
TimeFn = StrReplace(TimeFn, ":", "")
return
;----------------------------------------------------------------------
; SUBROUTINE: TimeDiffFormat
;----------------------------------------------------------------------/
:TimeDiffFormat
sd = 86400
sh = 3600
sm = 60
for i = 1 to 2
if i == 1 then x = p1
if (i == 2) && (p2 > 0)
x = p1 / p2
else
x = 0
endif
;format seconds to "DD:HH:MM:SS" string
d = 0
h = 0
m = 0
s = 0
if x / sd > 0
d = x / sd
x = x mod sd
endif
if x / sh > 0
h = x / sh
x = x mod sh
endif
if x / sm > 0
m = x / sm
x = x mod sm
endif
s = x
retval = StrCat(StrFixLeft(d, "0", 2), ":", StrFixLeft(h, "0", 2), ":", StrFixLeft(m, "0", 2), ":", StrFixLeft(s, "0", 2))
if i == 1 then retval1 = retval
if i == 2 then retval2 = retval
next
Drop(p1, p2, sd, sh, sm, d, h, m, s, x, retval)
return
;----------------------------------------------------------------------
; SUBROUTINE: DisplayMessage
;----------------------------------------------------------------------/
:DisplayMessage
s = StrReplace(MsgTxt, "|", C2)
if Task < 2
;RUN
if IsDefined(AppName)
if StrLen(AppName) > 1 then PNAME = AppName
endif
Message(PNAME, s)
else
;all other options
Display(3, PNAME, s)
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: SendNotification
;----------------------------------------------------------------------/
:SendNotification
;set up message text
NotificationText = StrCat("%PNAME%: ", NotificationText, " ERROR=%ErrorLevel%")
nerrtxt = "%PNAME%: Error Sending Notification"
subject = "%PNAME%: Alert"
;write to NT Event Log
if EventLog
if Task > 1
Run(LogEventPath, StrCat('"', NotificationText, '"'))
endif
endif
;this is how many notifications we will need to send out
ic = ItemCount(AlertList, "|")
;send email notifications, one per
;if unsuccessful, record in the NT Event Log
if SendEmail
for i = 1 to ic
;for each operator on the alert list
toaddr = ItemExtract(i, AlertList, "|")
ErrorMode(@OFF)
result = smtpSendText(MailServer, FromAddress, toaddr, subject, NotificationText)
ErrorMode(@CANCEL)
if !result
if Task > 1
Run(LogEventPath, StrCat('"', nerrtxt, '"'))
endif
endif
next
endif
;send pager notifications, one-shot
;if unsuccessful, record in the NT Event Log
if SendPage
key = ""
for i = 1 to ic
;for each operator on the alert list
k = ItemExtract(i, PagerKeyList, "|")
key = StrCat(key, k, ",")
next
key = StrSub(key, 1, StrLen(key) - 1)
ptext = StrCat("key: ", key, @CRLF, "msg: ", NotificationText)
ErrorMode(@OFF)
result = smtpSendText(MailServer, FromAddress, PagingAddress, subject, ptext)
ErrorMode(@CANCEL)
if !result
if Task > 1
Run(LogEventPath, StrCat('"', nerrtxt, '"'))
endif
endif
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: SendReport
;----------------------------------------------------------------------/
:SendReport
nerrtxt = "%PNAME%: Error Sending Statistics"
subject = "%PNAME%: Statistics Report"
if Notification
ErrorMode(@OFF)
result = smtpSendFile(MailServer, FromAddress, ReportAddress, subject, p1)
ErrorMode(@CANCEL)
if !result
;report can only be run from NT
Run(LogEventPath, StrCat('"', nerrtxt, '"'))
endif
endif
return
;----------------------------------------------------------------------
; SUBROUTINE: DisplayVerInfo
;----------------------------------------------------------------------/
:DisplayVerInfo
MsgTxt = VERINFO
gosub DisplayMessage
return
;----------------------------------------------------------------------
; SUBROUTINE: ErrorExit
;----------------------------------------------------------------------/
:ErrorExit
IntControl(1000, ErrorLevel, 0, 0, 0)
gosub DisplayMessage
if ErrorLevel > 2
MsgTxt = StrReplace(MsgTxt, "|", "@")
ErrTxt = "ERROR|RESPONSE=0|ERRORLEVEL=%ErrorLevel%|%MsgTxt%"
gosub WriteErrorFile
if Notification
gosub SendNotification
endif
;if running as a service, do not exit
if Task > 19 then return
endif
exit
return
;----------------------------------------------------------------------
; SUBROUTINE: ProgramExit
;----------------------------------------------------------------------/
:ProgramExit
IntControl(1000, ErrorLevel, 0, 0, 0)
exit
return
;----------------------------------------------------------------------
; SAMPLE INI FILE (save and remove semi-colons)
;----------------------------------------------------------------------/
;[Application]
;AppName=Symantec Visual Page
;AppFile=vpage.exe
;AppParms=
;
;[Run]
;AppPath=c:\app
;LicensePath=c:\app
;
;[Meter]
;AppPath=c:\app
;LicensePath=c:\app
;LogEventPath=c:\app
;
;[Notification]
;Notification=NO
;EventLog=YES
;AlertList=name1@yourdomain.com|name2@yourdomain.com
;PagerKeyList=pagerkey1|pagerkey2
;FromAddress=yourname@yourdomain.com
;ReportAddress=yourname@yourdomain.com
;NotificationText=An Error has occurred metering Symantec Visual Page. Please review the application error log for details.
;MailServer=mail.host.com
;PagingAddress=page@pager.host.com
;SendEmail=YES
;SendPage=YES
;SendShow=YES
;SendStats=YES
;
;[Service]
;MeterInterval=300
;MeterFrom=06:00
;MeterTo=18:00
;OpenLogOnStart=YES
;CloseLogOnStop=YES
;Application1=c:\app\pdcmeter.ini
;Application2=
;Application3=
Article ID: W13798
Filename: Software Metering Example.txt