home *** CD-ROM | disk | FTP | other *** search
- {$B-,D+,I-,R+,S+}
- {$O+} {so we can overlay this unit if we decide to}
-
- UNIT CommCDS;
-
- {
- ROB ROSENBERGER VOX: (618) 632-7345
- Barn Owl Software BBS: (618) 398-5703
- P.O. Box #74 HST: (618) 398-2305
- O'Fallon, IL 62269 CIS: 74017,1344
-
- Version 0.90 released to the public domain on 18 July 1989.
- This implementation does not support querying a phone bill analyzer for $$$
- cost information about a call in progress. It will be available in v1.00.
-
-
- This Turbo Pascal 5.0 unit offers complete support for the Call Data
- Standard as it applies to communications software. You can log all modem
- usage via simple, high-level routine calls. These modem usage details can
- then be used by CDS-compatible phone bill analyzer programs to calculate
- the total cost of using a modem.
- You can also determine the cost of a call in progress (or most recently
- ended) by using another simple high-level routine call. This unit will
- "query" a phone bill analyzer to calculate the cost of the call for you,
- and you can then show this information to the user. The effort to GET the
- information is a simple as a high-level routine call, but you yourself must
- put the information on the screen.
- This unit requires the Turbo Professional 5.0 toolkit from TurboPower
- Software. Write to them for a free brochure if you don't already have this
- powerful toolkit. TurboPower's address is P.O. Box #66747, Scotts Valley,
- CA 95066-0747.
- Contact Rob Rosenberger if you have any questions or comments about this
- unit or about the Call Data Standard.
-
- LIMITATIONS:
- CDS records 011, 012, and 013 are not implemented in this unit. They are
- of an esoteric nature. Consult the CDS specs for more information.
- CDS records 040 and 045 are limited to host BBS charges. You can modify
- it to work with phone company charges if you wish.}
-
-
- INTERFACE {section}
-
- USES
- DOS,
- TpDOS,
- TpDate,
- TpString;
-
- CONST
- ProgramName : STRING[08] = 'UNKNOWN'; {your program's name, max 8 chars}
- HostName : STRING[16] = ''; {navigation programs put their host
- service's name here. TAPCIS, for
- example, might use 'CompuServe'.
- Max length is 16 chars. Leave it
- null if your comm program is for
- general purpose communications.}
-
- TYPE
- CDSProtocolType
- = (UnknownProtocol,
- NoProtocolUsed,
- ASCII,
- Bimodem,
- CISA,
- CISB,
- CISQuickB,
- CISBPlus,
- Jmodem,
- Kermit,
- Modem7,
- Telink,
- Xmodem,
- Xmodem1K, {sometimes mistakenly referred to as Ymodem}
- Xmodem1KG,
- XmodemCRC,
- Ymodem, {the true Ymodem Batch protocol}
- YmodemG, {the true Ymodem Batch protocol}
- Zmodem);
-
- ReasonType
- = (UnknownReason,
- BusinessReason,
- PersonalReason);
-
- RecordTypeRDF
- = RECORD
- CDSverRDF : WORD; {RDF version; v1.00 = 100 and so on}
- ErrorValue : BYTE;
- CurrencyChar : CHAR;
-
- ComPort : BYTE;
- CommSpeed : LONGINT;
- DataBits : BYTE;
- Parity : CHAR;
- StopBits : BYTE;
-
- CommUserName : STRING[40];
- BusinessCall : ReasonType;
- HostBBSName : STRING[40];
- PhoneNumber : STRING[32];
- EndedAbrupt : BOOLEAN;
- CallStarted : DateTimeRec;
- CallEnded : DateTimeRec;
- ElapsedTime : Time;
- AvgCPS4Call : WORD; {zero if unknown}
- AvgEff4Call : REAL; {zero if unknown}
- UploadXfers : BYTE; {sucessful uploads}
- UploadAborts : BYTE; {aborted uploads}
- DnloadXfers : BYTE; {successful downloads}
- DnloadAborts : BYTE; {aborted downloads}
- AvgCPS4Xfers : WORD; {zero if unknown}
- AvgEff4Xfers : REAL; {zero if unknown}
- PhoneCost : REAL;
- BBSCost : REAL
- END;
-
- VAR
- CDSIORESULT : BYTE; {always contains the value of IORESULT}
- RDFRecord : RecordTypeRDF;
-
- PROCEDURE ChangeCallParams(CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- HostBBSName : STRING;
- SecurityLevel : INTEGER;
- Comment : STRING);
- PROCEDURE GetCostOfCall(CDSProgName : PathStr);
- PROCEDURE InitCommCDS(CDSPath : STRING);
- PROCEDURE LogChargeChange(Suspend : BOOLEAN;
- Comment : STRING);
- PROCEDURE LogFileXfer(FileName : STRING;
- WasUploaded : BOOLEAN;
- FileSize : LONGINT;
- Reason4Transfer : ReasonType;
- Protocol : CDSProtocolType;
- SuspendBBSCharge : BOOLEAN;
- StartingDateTime : DateTimeRec;
- EndingDateTime : DateTimeRec;
- AbortedBySender : BOOLEAN;
- AbortedByRecvr : BOOLEAN;
- CallDiedInXfer : BOOLEAN;
- TotalXmitErrors : WORD;
- Efficiency : REAL;
- AverageCPS : WORD;
- Comment : STRING);
- PROCEDURE LogForumSwitch(ForumName : STRING;
- Comment : STRING);
- PROCEDURE LogFreeFormatComment(CommentString : STRING);
- PROCEDURE LogIncomingCall(CommPort : INTEGER;
- CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- SecurityLevel : INTEGER;
- LocalLogon : BOOLEAN;
- Comment : STRING);
- PROCEDURE LogOutgoingCall(CommPort : INTEGER;
- CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- Reason4Call : ReasonType;
- HostBBSName : STRING;
- PhoneNumber : STRING;
- HostCallback : BOOLEAN;
- Comment : STRING);
- PROCEDURE LogTerminatedCall(PasswordFailure : BOOLEAN;
- CallContinuedOn : BOOLEAN;
- CallEndedAbrupt : BOOLEAN;
- AverageCPS : WORD;
- Comment : STRING);
- PROCEDURE WrapupCommCDS;
-
-
- IMPLEMENTATION {section}
-
- CONST
- DirStrLen = 67;
-
- Colon = ':';
- Dash = '-';
- NullChar = #0;
- NullString = '';
- Space = ' ';
- TabChar = #9;
-
- OutgoingCallID = 001;
- HostCallbackID = 002;
- HostCallerID = 003;
- ChangeParamsID = 008;
- EndedCallID = 009;
- FileXferID = 020;
- SwitchForumID = 030;
- SuspendChargeID = 040;
- ResumeChargeID = 045;
- CommentID = 255;
-
- CDSext = '.CDS';
- SCFext = '.SCF';
- RDFext = '.RDF';
-
- TpDateForm = 'yy/mm/dd ';
- TpTimeForm = 'hh:mm:ss ';
-
- MaxOneLineCommentLength = 56;
-
- CONST {typed}
- CDSProtocolIDs : ARRAY [CDSProtocolType] OF STRING[11]
- = ('UNKNOWN',
- 'NONE',
- 'ASCII',
- 'Bimodem',
- 'CIS-A',
- 'CIS-B',
- 'CIS-QuickB',
- 'CIS-Bplus',
- 'Jmodem',
- 'Kermit',
- 'Modem7',
- 'Telink',
- 'Xmodem',
- 'Xmodem-1K',
- 'Xmodem-1K-G',
- 'Xmodem-CRC',
- 'Ymodem',
- 'Ymodem-G',
- 'Zmodem');
-
- DefaultCDSPath : DirStr = NullString;
-
- TYPE
- DirStr = STRING[DirStrLen];
-
- VAR
- CDS : TEXT; {the call history file}
- SCF : TEXT; {the single call file}
- RDF : TEXT; {the return data file}
- BufferCDS : ARRAY [1..1024] OF CHAR;
- BufferSCF : ARRAY [1..1024] OF CHAR;
-
- RewriteSCF : BOOLEAN;
- ActiveCall : BOOLEAN;
- OutgoingCall : BOOLEAN;
-
- CommentInProgress : BOOLEAN;
-
- CallStarted : DateTimeRec;
- CallEnded : DateTimeRec;
- CallElapsed : Time;
- XferStarted : DateTimeRec;
- XferEnded : DateTimeRec;
- XferElapsed : Time;
-
- CDSStartingDateTime : DateTimeRec;
-
- OldTpDateSep : CHAR;
- OldTpTimeSep : CHAR;
-
- Port : INTEGER;
- Speed : LONGINT;
- DataBits : BYTE;
- Parity : CHAR;
- StopBits : BYTE;
-
- {============================================================================}
- PROCEDURE CloseCDSFiles;
- {This is an internal procedure.}
-
- {This procedure closes the CDS call history file and the CDS single call
- file.}
-
- {============================================================================}
- PROCEDURE RestoreTpDateSeps;
- {This is an internal procedure.}
-
- {This procedure returns TpDate to its previous settings. Use it after a
- call to the ModifyTpDateSeps procedure.}
-
- BEGIN {RestoreTpDateSeps}
- SlashChar := OldTpDateSep;
- ColonChar := OldTpTimeSep
- END; {RestoreTpDateSeps}
- {============================================================================}
-
- BEGIN {CloseCDSFiles}
- CLOSE(CDS);
- CLOSE(SCF);
- RestoreTpDateSeps
- END; {CloseCDSFiles}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogCDSRecord(RecordValue : BYTE);
- {This is an internal procedure.}
-
- {This procedure logs the master record identifier for a given CDS entry.}
-
- {============================================================================}
- PROCEDURE WriteCDSRecord(VAR F : TEXT);
- {This is an internal procedure.}
-
- {This procedure writes the actual CDS record. It is a routine in its own
- right because the same record will be written to multiple CDS files.}
-
- BEGIN {WriteCDSRecord}
- WRITELN(F);
- WRITE(F,DateToDateString(TpDateForm,CDSStartingDateTime.D),
- TimeToTimeString(TpTimeForm,CDSStartingDateTime.T));
- CASE RecordValue OF
- 0..9 : WRITE(F,'00',RecordValue,Space);
- 10..99 : WRITE(F,'0',RecordValue,Space);
- ELSE WRITE(F,RecordValue,Space)
- END; {CASE}
- WRITELN(F,ProgramName);
-
- IF ((RecordValue <> CommentID) OR ((RecordValue = CommentID) AND ActiveCall))
- THEN WRITELN(F,TabChar,'COM port ',Port)
- END; {WriteCDSRecord}
- {============================================================================}
-
- BEGIN {LogCDSRecord}
- {Initialize.}
- IF (CDSStartingDateTime.D = BadDate)
- THEN {use the current date & time}
- WITH CDSStartingDateTime
- DO BEGIN
- D := Today;
- T := CurrentTime
- END;
- {ELSE use the supplied date & time}
-
- WriteCDSRecord({VAR} CDS);
- WriteCDSRecord({VAR} SCF);
-
- {Wrapup.}
- CDSStartingDateTime.D := BadDate
- END; {LogCDSRecord}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE OpenCDSFiles;
- {This is an internal procedure.}
-
- {This procedure opens the CDS call history file and the CDS single call
- file for output.}
-
- {============================================================================}
- PROCEDURE ModifyTpDateSeps;
- {This is an internal procedure.}
-
- {This procedure adjusts TpDate to CDS needs. Use the RestoreTpDateSeps
- procedure before returning control to the comm program.}
-
- BEGIN {ModifyTpDateSeps}
- OldTpDateSep := SlashChar;
- OldTpTimeSep := ColonChar;
-
- SlashChar := Dash;
- ColonChar := Colon
- END; {ModifyTpDateSeps}
- {============================================================================}
-
- BEGIN {OpenCDSFiles}
- IF ExistFile(DefaultCDSPath + ProgramName + CDSext)
- THEN APPEND(CDS)
- ELSE REWRITE(CDS);
-
- IF RewriteSCF
- THEN
- BEGIN
- REWRITE(SCF);
- RewriteSCF := FALSE
- END
- ELSE
- APPEND(SCF);
-
- SETTEXTBUF(CDS,BufferCDS);
- SETTEXTBUF(SCF,BufferSCF);
-
- ModifyTpDateSeps
- END; {OpenCDSFiles}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteCommDetails(VAR F : TEXT);
- {This is an internal procedure.}
-
- {This procedure writes comm speed/parity/stop bit details about the call.
- It is a procedure in its own right because the details must be logged in
- multiple CDS files. It is up to the calling routine to check IORESULT.}
-
- BEGIN {WriteCommDetails}
- WRITELN(F,TabChar,'Comm parameters ',
- Speed,Space,DataBits,Space,Parity,Space,StopBits);
- END; {WriteCommDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteFileXferDetails(VAR F : TEXT;
- FileName : STRING;
- WasUploaded : BOOLEAN;
- FileSize : LONGINT;
- Reason4Transfer : ReasonType;
- Protocol : CDSProtocolType;
- SuspendBBSCharge : BOOLEAN;
- EndingDateTime : DateTimeRec;
- AbortedBySender : BOOLEAN;
- AbortedByRecvr : BOOLEAN;
- CallDiedInXfer : BOOLEAN;
- TotalXmitErrors : WORD;
- Efficiency : REAL;
- AverageCPS : WORD);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about a file transfer. It is
- a procedure in its own right because these details must be logged in multiple
- CDS files.}
-
- VAR
- Days : WORD;
- Secs : LONGINT;
-
- Hours : BYTE;
- Minutes : BYTE;
- Seconds : BYTE;
-
- BEGIN {WriteFileXferDetails}
- {Initialize.}
- Filename := StUpCase(JustFilename(Filename));
-
- WriteCommDetails({VAR} F);
-
- IF WasUploaded
- THEN WRITELN(F,TabChar,'Sent file ',Filename)
- ELSE WRITELN(F,TabChar,'Rcvd file ',Filename);
-
- WRITELN(F,TabChar,'File size ',FileSize);
-
- IF (Reason4Transfer = UnknownReason)
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- IF (Reason4Transfer = BusinessReason)
- THEN WRITE(F,TabChar,'Business ')
- ELSE WRITE(F,TabChar,'Personal ');
- WRITELN(F,' file transfer')
- END;
-
- WRITELN(F,TabChar,'Protocol ',CDSProtocolIDs[Protocol]);
-
- IF SuspendBBSCharge
- THEN
- BEGIN
- WRITE(F,TabChar,'Suspend host charges');
- IF (Hostname = NullString)
- THEN WRITELN(F)
- ELSE WRITELN(F,' (',Hostname,')')
- END;
-
- WRITE(F,TabChar,
- 'Ended ',
- DateToDateString(TpDateForm,EndingDateTime.D),
- TimeToTimeString(TpTimeForm,EndingDateTime.T));
- IF AbortedBySender
- THEN
- WRITELN(F,' (aborted by sender)')
- ELSE
- IF AbortedByRecvr
- THEN
- WRITELN(F,' (aborted by receiver)')
- ELSE
- IF CallDiedInXfer
- THEN
- WRITELN(F,' (call ended abruptly)')
- ELSE
- WRITELN(F);
-
- DateTimeDiff(XferStarted,XferEnded,{VAR} Days,{VAR} Secs);
- TimeToHMS(Secs,{VAR} Hours,{VAR} Minutes,{VAR} Seconds);
- INC(Hours,(Days * HoursInDay));
- IF (Hours < 10)
- THEN WRITE(F,TabChar,'Elapsed time ','0',Hours,Colon)
- ELSE WRITE(F,TabChar,'Elapsed time ',Hours,Colon);
- IF (Minutes < 10)
- THEN WRITE(F,'0',Minutes,Colon)
- ELSE WRITE(F,Minutes,Colon);
- IF (Seconds < 10)
- THEN WRITELN(F,'0',Seconds)
- ELSE WRITELN(F,Seconds);
-
- IF (TotalXmitErrors > 0)
- THEN WRITELN(F,TabChar,'Transfer Errors ',TotalXmitErrors);
-
- IF (Efficiency > 0)
- THEN WRITELN(F,TabChar,'Efficiency ',Efficiency:1:1,' %');
-
- IF (AverageCPS > 0)
- THEN WRITELN(F,TabChar,'Average CPS ',AverageCPS)
- END; {WriteFileXferDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteFirstCommentLine(VAR F : TEXT);
- {This is an internal procedure.}
-
- {This procedure writes the first comment line of a multi-line free-format
- comment.}
-
- BEGIN {WriteFirstCommentLine}
- WRITELN(F,TabChar,'COMMENT: ')
- END; {WriteFirstCommentLine}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteForumSwitchDetails(VAR F : TEXT;
- ForumName : STRING);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about a user who is switching
- between forums of a host system.}
-
- BEGIN {WriteForumSwitchDetails}
- IF (ForumName = NullString)
- THEN EXIT; {no need to hang around, eh?}
- IF (LENGTH(ForumName) > 16)
- THEN ForumName[0] := #16;
-
- WRITELN(F,TabChar,'Moved to forum ',ForumName)
- END; {WriteForumSwitchDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteFreeFormatComment(VAR F : TEXT;
- Comment : STRING);
- {This is an internal procedure.}
-
- {This procedure writes a free-format comment to the given CDS file. It
- performs word-wrapping for the comment string, if necessary. It does NOT
- truncate the string.}
-
- CONST
- CommentMargin = 65;
-
- VAR
- OutString : STRING;
- Overlap : STRING;
-
- BEGIN {WriteFreeFormatComment}
- REPEAT
- WordWrap(Comment,
- {VAR} OutString,
- {VAR} Comment,
- CommentMargin,
- FALSE); {no padding desired}
- WRITELN(F,TabChar,OutString);
- UNTIL (Comment = NullString);
- END; {WriteFreeFormatComment}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteIncomingCallDetails(VAR F : TEXT;
- CallerName : STRING;
- SecurityLevel : INTEGER;
- LocalLogon : BOOLEAN);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about an incoming call. It is
- a procedure in its own right because these details must be logged in multiple
- CDS files.}
-
- BEGIN {WriteIncomingCallDetails}
- WriteCommDetails({VAR} F);
-
- IF (CallerName = NullString)
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- IF (LENGTH(CallerName) > 40)
- THEN CallerName[0] := #40;
- WRITELN(F,TabChar,'Connected with ',CallerName)
- END;
-
- IF LocalLogon
- THEN WRITELN(F,TabChar,'Local logon');
-
- WRITELN(F,TabChar,'Security level ',SecurityLevel)
- END; {WriteIncomingCallDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteOneLineComment(VAR F : TEXT;
- Comment : STRING);
- {This is an internal procedure.}
-
- {This procedure writes a one-line comment if it is provided. Comments are
- truncated if they exceed the maximum allowable length.}
-
- BEGIN {WriteOneLineComment}
- IF (Comment = NullString)
- THEN EXIT; {no need to hang around here}
-
- IF (LENGTH(Comment) > MaxOneLineCommentLength)
- THEN Comment[0] := CHR(MaxOneLineCommentLength);
-
- WRITELN(F,TabChar,'Comment: ',Comment)
- END; {WriteOneLineComment}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteOutgoingCallDetails(VAR F : TEXT;
- CallerName : STRING;
- Reason4Call : ReasonType;
- HostBBSName : STRING;
- PhoneNumber : STRING;
- IgnorePhNbr : BOOLEAN);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about an outgoing call. It is
- a procedure in its own right because these details must be logged in multiple
- CDS files.}
-
- BEGIN {WriteOutgoingCallDetails}
- WriteCommDetails({VAR} F);
-
- IF (CallerName = NullString)
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- IF (LENGTH(CallerName) > 40)
- THEN CallerName[0] := #40;
- WRITELN(F,TabChar,'Caller was ',CallerName)
- END;
-
- IF (Reason4Call = UnknownReason)
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- IF (Reason4Call = BusinessReason)
- THEN WRITE(F,TabChar,'Business ')
- ELSE WRITE(F,TabChar,'Personal ');
- WRITELN(F,' call')
- END;
-
- IF (HostBBSName = NullString)
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- IF (LENGTH(HostBBSName) > 40)
- THEN HostBBSName[0] := #40;
- WRITELN(F,TabChar,'Connected with ',HostBBSName)
- END;
-
- IF (PhoneNumber = NullString)
- THEN
- IF IgnorePhNbr
- THEN {null}
- ELSE WRITELN(F,TabChar,'CALL WAS ALREADY IN PROGRESS')
- ELSE
- BEGIN
- IF (LENGTH(PhoneNumber) > 32)
- THEN PhoneNumber[0] := #32;
- WRITELN(F,TabChar,'Phone number ',PhoneNumber)
- END
- END; {WriteOutgoingCallDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteChargeDetails(VAR F : TEXT;
- Suspend : BOOLEAN;
- HostBBS : BOOLEAN;
- PhoneCo : BOOLEAN);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about suspending or resuming
- phone company or host BBS charges.}
-
- VAR
- TheText : STRING[7];
-
- BEGIN {WriteResumeChargeDetails}
- IF Suspend
- THEN TheText := 'Suspend'
- ELSE TheText := 'Resume';
-
- IF HostBBS
- THEN
- BEGIN
- WRITE(F,TabChar,TheText,' host charges');
- IF (HostName = NullString)
- THEN WRITELN(F)
- ELSE WRITELN(F,' (',HostName,')')
- END;
-
- IF PhoneCo
- THEN WRITELN(F,TabChar,TheText,' phone charges')
- END; {WriteResumeChargeDetails}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WriteTerminatedCallDetails(VAR F : TEXT;
- PasswordFailure : BOOLEAN;
- CallContinuedOn : BOOLEAN;
- CallEndedAbrupt : BOOLEAN;
- AverageCPS : WORD);
- {This is an internal procedure.}
-
- {This procedure writes specific CDS details about a terminated call. It is
- a procedure in its own right because these details must be logged in multiple
- CDS files.}
-
- VAR
- Days : WORD;
- Secs : LONGINT;
-
- Hours : BYTE;
- Minutes : BYTE;
- Seconds : BYTE;
-
- BEGIN {WriteTerminatedCallDetails}
- IF PasswordFailure
- THEN WRITELN(F,TabChar,'FAILED TO PROVIDE PASSWORD');
-
- IF CallContinuedOn
- THEN
- WRITELN(F,TabChar,'CALL REMAINED IN PROGRESS')
- ELSE
- IF CallEndedAbrupt
- THEN WRITELN(F,TabChar,'Call ended abruptly');
-
- DateTimeDiff(CallStarted,CallEnded,{VAR} Days,{VAR} Secs);
- TimeToHMS(Secs,{VAR} Hours,{VAR} Minutes,{VAR} Seconds);
- INC(Hours,(Days * HoursInDay));
- IF (Hours < 10)
- THEN WRITE(F,TabChar,'Elapsed time ','0',Hours,Colon)
- ELSE WRITE(F,TabChar,'Elapsed time ',Hours,Colon);
- IF (Minutes < 10)
- THEN WRITE(F,'0',Minutes,Colon)
- ELSE WRITE(F,Minutes,Colon);
- IF (Seconds < 10)
- THEN WRITELN(F,'0',Seconds)
- ELSE WRITELN(F,Seconds);
-
- IF (AverageCPS > 0)
- THEN WRITELN(F,TabChar,'Average CPS ',AverageCPS)
- END; {WriteTerminatedCallDetails}
- {============================================================================}
-
-
- {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
-
-
- {============================================================================}
- PROCEDURE ChangeCallParams(CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- HostBBSName : STRING;
- SecurityLevel : INTEGER;
- Comment : STRING);
-
- {This procedure lets you change the OPTIONAL details of a call which is
- already in progress.
- CommSpeed, CommBits, CommParity, and CommStopBits must always be supplied
- with their proper values when invoking this routine.
- CallerName and HostBBSName are written out to the CDS files only if they
- contain data. Null strings are ignored.
- SecurityLevel is written out in all cases where the call was taken by the
- host mode. This unit knows when an active call is a host call (including any
- call which is a security host callback).
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {ChangeCallParams}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- Speed := CommSpeed;
- DataBits := CommBits;
- Parity := CommParity;
- StopBits := CommStopBits;
-
- LogCDSRecord(ChangeParamsID);
- IF OutgoingCall
- THEN
- BEGIN
- WriteOutgoingCallDetails({VAR} CDS,
- CallerName,
- UnknownReason, {don't touch call reason}
- HostBBSName,
- NullString,
- TRUE);
- WriteOutgoingCallDetails({VAR} SCF,
- CallerName,
- UnknownReason, {don't touch call reason}
- HostBBSName,
- NullString,
- TRUE)
- END
- ELSE
- BEGIN
- WriteIncomingCallDetails({VAR} CDS,
- CallerName,
- SecurityLevel,
- FALSE);
- WriteIncomingCallDetails({VAR} SCF,
- CallerName,
- SecurityLevel,
- FALSE)
- END;
- WriteOneLineComment({VAR} CDS,Comment);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
-
- END; {ChangeCallParams}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE GetCostOfCall(CDSProgName : PathStr);
-
- {This procedure queries the CDS program defined in CDSProgName for the cost
- of the call defined in the SCF file. This procedure can be called any time,
- even if the call is still in progress.
-
- ErrorValue returns with a zero to indicate success. Any other value is a
- failure; all other fields are undefined. Current ErrorValue codes:
- 0 -- Success
- 1 -- PRF file was invalid or not found
- 2 -- PRF file complies to unknown CDS standard
- 3 -- error dealing with the SCF file
- 4 -- not enough memory for phone bill analyzer
- 255 -- phone bill analyzer aborted
-
- You must still check CDSIORESULT after calling this procedure. Checking the
- ErrorValue is not enough.}
-
- BEGIN {GetCostOfCall}
- {Initialize.}
- ASSIGN(RDF,(DefaultCDSPath + ProgramName + RDFext));
- ERASE(RDF);
- FILLCHAR(RDFRecord,SIZEOF(RDFRecord),NullChar);
-
- {Execute the CDS phone bill analyzer.}
- CDSIORESULT := ExecDOS((CDSProgName + ' /CDS'
- + DefaultCDSPath + ProgramName + SCFext
- + ','
- + DefaultCDSPath + ProgramName + RDFext),
- TRUE,NIL);
-
- {Did we get back a CDS RDF file?}
- IF ExistFile(DefaultCDSPath + ProgramName + RDFext)
- THEN
-
- ELSE
- BEGIN
- {Read the CDS RDF file.}
- RESET(RDF);
-
- END
- END; {GetCostOfCall}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE InitCommCDS(CDSPath : STRING);
-
- {This procedure initializes the CommCDS unit. It MUST be called before
- any other routine in this unit.
- CDSPath specifies a path for all CDS files. Set this to a null string for
- the default drive & directory.}
-
- BEGIN {InitCommCDS}
- CDSIORESULT := 0;
- DefaultCDSPath := AddBackslash(CDSPath);
-
- ASSIGN(CDS,(DefaultCDSPath + ProgramName + CDSext));
- ASSIGN(SCF,(DefaultCDSPath + ProgramName + SCFext));
-
- RewriteSCF := TRUE;
- ActiveCall := FALSE;
-
- CommentInProgress := FALSE;
-
- CDSStartingDateTime.D := BadDate
- END; {InitCommCDS}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogChargeChange(Suspend : BOOLEAN;
- Comment : STRING);
-
- {This procedure suspends or resumes host BBS or phone company charges, as
- reflected in the CDS files. It specifically overrides any assumptions made by
- phone bill analyzers about charges for the call. This is extremely handy in
- navigation software like TAPCIS when uploading. CompuServe suspends charges
- during an upload, and continues suspending charges while the user types in a
- description for the file. TAPCIS could therefore show exactly when charges
- were suspended and when they finally resumed again.
- Suspend dictates whether charges are being suspended or resumed.
- HostBBS dictates whether this applies to host charges.
- PhoneCo dictates whether this applies to phone company charges.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {LogChargeChange}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- IF Suspend
- THEN LogCDSRecord(SuspendChargeID)
- ELSE LogCDSRecord(ResumeChargeID);
- WriteChargeDetails({VAR} CDS,Suspend,TRUE,FALSE);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteChargeDetails({VAR} SCF,Suspend,TRUE,FALSE);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogChargeChange}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogFileXfer(FileName : STRING;
- WasUploaded : BOOLEAN;
- FileSize : LONGINT;
- Reason4Transfer : ReasonType;
- Protocol : CDSProtocolType;
- SuspendBBSCharge : BOOLEAN;
- StartingDateTime : DateTimeRec;
- EndingDateTime : DateTimeRec;
- AbortedBySender : BOOLEAN;
- AbortedByRecvr : BOOLEAN;
- CallDiedInXfer : BOOLEAN;
- TotalXmitErrors : WORD;
- Efficiency : REAL;
- AverageCPS : WORD;
- Comment : STRING);
-
- {The modem's speed, parity, and stop bits are assumed to be the same as they
- were previously. The comm program must invoke ChangeCallParams if it wants to
- use a different setting for these values.
- Filename is the name of the file being transferred. This procedure will
- remove the drive & path from any filename you send it.
- WasUploaded dictates if the file was uploaded or downloaded.
- FileSize is the size of the transferred file.
- Reason4Transfer dictates whether this transfer took place for business
- reasons, for personal reasons, or for unknown reasons.
- Protocol is the CDS protocol used for the file transfer.
- SuspendBBSCharge dictates whether the host computer is suspending charges
- during this file transfer.
- Starting/EndingDate/Time denote the date/time the transfer started/ended.
- AbortedBySender is TRUE only if the uploader aborted the transfer.
- AbortedByRecvr is TRUE only if the downloader aborted the transfer.
- CallDiedInXfer is TRUE only if the call terminated abruptly during the file
- transfer.
- TotalXmitErrors designates the number of bad blocks that appeared during
- the transfer.
- Efficiency is the relative efficiency of the transfer. This number appears
- in CDS files with an accuracy of at least 0.1, but of course the accuracy is
- strictly up to you. A 97.2% efficiency would be stored in this variable as
- 97.2. The value is left out of the CDS activity log entirely if you supply a
- value of 0.0.
- AverageCPS is the average chars per second for the overall transfer. It is
- left out of the CDS activity log entirely if you supply a valud of 0.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {LogFileXfer}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
- XferStarted := StartingDateTime;
- XferEnded := EndingDateTime;
-
- CDSStartingDateTime := StartingDateTime;
- LogCDSRecord(FileXferID);
- WriteFileXferDetails({VAR} CDS,
- FileName,
- WasUploaded,
- FileSize,
- Reason4Transfer,
- Protocol,
- SuspendBBSCharge,
- EndingDateTime,
- AbortedBySender,
- AbortedByRecvr,
- CallDiedInXfer,
- TotalXmitErrors,
- Efficiency,
- AverageCPS);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteFileXferDetails({VAR} SCF,
- FileName,
- WasUploaded,
- FileSize,
- Reason4Transfer,
- Protocol,
- SuspendBBSCharge,
- EndingDateTime,
- AbortedBySender,
- AbortedByRecvr,
- CallDiedInXfer,
- TotalXmitErrors,
- Efficiency,
- AverageCPS);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogFileXfer}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogForumSwitch(ForumName : STRING;
- Comment : STRING);
-
- {This procedure logs a switch between various forums, or conference areas,
- of a host computer system. This includes when the comm program is [acting as]
- a BBS.
- ForumName is the name of the new forum. It will be truncated if it exceeds
- 16 chars. Note: CDS phone bill analyzers automatically assume the first forum
- is an "overhead" which encompasses the logon procedure. You would be wise to
- log that you switched to the "main" forum (or whatever) when you reach a known
- landmark in the host system.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {LogForumSwitch}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- LogCDSRecord(SwitchForumID);
- WriteForumSwitchDetails({VAR} CDS,ForumName);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteForumSwitchDetails({VAR} SCF,ForumName);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogForumSwitch}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogFreeFormatComment(CommentString : STRING);
-
- {This procedure adds a free-format comment to the CDS log.}
-
- {NOTE: This procedure works different from all other procedures. There is
- only one CommentString variable -- however, you may call this procedure as
- many times as it takes to send your entire comment down the line. The only
- requirement is that you MUST end the comment by calling this procedure with
- a null string as the CommentString. This signals you are finished with your
- free-format comment.
- CDSIORESULT is NOT initialized until a comment has been ended. Check the
- value *after* you call this procedure with a null string.
- The CommentString can be any length you want. Word-wrapping is performed
- as necessary to make the string fit within CDS constraints. A CR/LF is added
- to the end of each CommentString. Please be aware of this if you want to use
- special formatting for each string.
- Comments are automatically 'tied' to a phone call if a call is in progress.
- Otherwise they are considered 'generic', or global, comments in the CDS log.}
-
- BEGIN {LogFreeFormatComment}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- IF (CommentString = NullString)
- THEN
- CommentInProgress := FALSE
- ELSE
- BEGIN
- IF CommentInProgress
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- {Begin a comment in the CDS logs.}
- CDSStartingDateTime.D := BadDate;
- LogCDSRecord(CommentID);
-
- WriteFirstCommentLine({VAR} CDS);
- WriteFirstCommentLine({VAR} SCF);
- CommentInProgress := TRUE
- END;
-
- WriteFreeFormatComment({VAR} CDS,CommentString);
- WriteFreeFormatComment({VAR} SCF,CommentString);
- END;
-
- {Wrapup ONLY if the comment is complete.}
- IF CommentInProgress
- THEN
- {Do nothing.}
- ELSE
- BEGIN
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END
- END; {LogFreeFormatComment}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogIncomingCall(CommPort : INTEGER;
- CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- SecurityLevel : INTEGER;
- LocalLogon : BOOLEAN;
- Comment : STRING);
-
- {This procedure logs an incoming call.}
-
- {CallerName is the name of the person who called. You should determine who
- the caller is before you invoke this routine. Use 'UNKNOWN' (all caps) if the
- caller hangs up before giving a name. Use 'SYSOP' (all caps) if the sysop is
- logging in. CallerName is truncated if it exceeds 40 chars.
- SecurityLevel is the security access authorized for the caller. It can be
- a negative number if you use them as access levels.
- LocalLogon is TRUE if the logon is occuring at the local site. This is a
- common occurance when sysops log in, for example.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable lenght.}
-
- BEGIN {LogIncomingCall}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- {Set up the call in progress.}
- RewriteSCF := TRUE;
- ActiveCall := TRUE;
- OutgoingCall := FALSE;
-
- Port := CommPort;
- Speed := CommSpeed;
- DataBits := CommBits;
- Parity := CommParity;
- StopBits := CommStopBits;
-
- CDSStartingDateTime := CallStarted;
- LogCDSRecord(HostCallerID);
- WriteIncomingCallDetails({VAR} CDS,
- CallerName,
- SecurityLevel,
- LocalLogon);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteIncomingCallDetails({VAR} SCF,
- CallerName,
- SecurityLevel,
- LocalLogon);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogIncomingCall}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogOutgoingCall(CommPort : INTEGER;
- CommSpeed : LONGINT;
- CommBits : BYTE;
- CommParity : CHAR;
- CommStopBits : BYTE;
- CallerName : STRING;
- Reason4Call : ReasonType;
- HostBBSName : STRING;
- PhoneNumber : STRING;
- HostCallback : BOOLEAN;
- Comment : STRING);
-
- {This procedure logs an outgoing call. It assumes the starting date/time
- of the call is RIGHT NOW. You should log a call the instant you detect it.
-
- CallerName is normally a null string, except in cases like TAPCIS where it
- should be filled with the userID of the person calling. Some programs, such
- as QMODEM, accept the person's name as part of the registration process, and
- therefore might want to use that as the CallerName. CallerName is truncated
- if it exceeds 40 chars.
- HostBBSName is usually known, but there are exceptions. You won't know the
- name of a BBS when you perform a manual dial, so use "UNKNOWN" (all caps) for
- the name. The same holds true if you suddenly detect a call which probably
- occurred when someone typed an AT dialing command directly to the modem.
- HostBBSName is truncated if it exceeds 40 chars.
- PhoneNumber obviously contains the phone number. If this is a null string,
- it means you have no idea what the phone number was. This could be due to a
- user typing an AT dialing command directly to the modem, or a call that is
- already in progress when the program first starts up. PhoneNumber is trun-
- cated if it exceeds 32 chars.
- NOTE ABOUT PHONE NUMBERS: Vanity numbers such as "1-800-DEC-DEMO" are not
- allowed in CDS. You *must* convert them to their equivalent numeric format
- before calling this procedure. CDS phone bill analyzers view letters in the
- phone number as redefinable prefix/suffix codes. Consult the CDS proposal
- document for further information.
- HostCallback is TRUE only when the comm program is in a host mode and has
- been activated to return a call, rather than to place a call. In this case,
- the comm program should use 'Security Callback Feature' or something similar
- as the CallerName, and use the logon attempter's name as the HostBBSName.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {LogOutgoingCall}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- {Set up the call in progress.}
- ActiveCall := TRUE;
- WITH CallStarted
- DO BEGIN
- D := Today;
- T := CurrentTime
- END;
- OutgoingCall := TRUE;
- Port := CommPort;
- Speed := CommSpeed;
- DataBits := CommBits;
- Parity := CommParity;
- StopBits := CommStopBits;
-
- IF HostCallback
- THEN LogCDSRecord(HostCallbackID)
- ELSE LogCDSRecord(OutgoingCallID);
- WriteOutgoingCallDetails({VAR} CDS,
- CallerName,
- Reason4Call,
- HostBBSName,
- PhoneNumber,
- FALSE);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteOutgoingCallDetails({VAR} SCF,
- CallerName,
- Reason4Call,
- HostBBSName,
- PhoneNumber,
- FALSE);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogOutgoingCall}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE LogTerminatedCall(PasswordFailure : BOOLEAN;
- CallContinuedOn : BOOLEAN;
- CallEndedAbrupt : BOOLEAN;
- AverageCPS : WORD;
- Comment : STRING);
-
- {This procedure logs the termination of a call. It assumes the ending
- date/time is RIGHT NOW. You should log a termination as soon as it is
- detected.
-
- PasswordFailure indicates a host caller was terminated because of multiple
- failed attempts to provide the proper password.
- CallContinuedOn indicates the call has NOT actually ended. It means the
- program is terminating when a call will still be going on.
- CallEndedAbrupt indicates a call ended abruptly. This is true in cases
- where the carrier is lost during a file transfer, for example. Navigation
- software (such as TAPCIS) may recognize a call terminated abnormally, and can
- set this to TRUE.
- AverageCPS is the average chars per second over the entire call. It is up
- to the comm program to decide what value this contains. A value of zero means
- there will be no record of the average CPS in the CDS files.
- Comment is any text you wish to add to the CDS record. It is truncated if
- it exceeds the maximum allowable length.}
-
- BEGIN {LogTerminatedCall}
- {Initialize.}
- CDSIORESULT := 0;
- OpenCDSFiles;
-
- {Wrap up the call in progress.}
- ActiveCall := FALSE;
- WITH CallEnded
- DO BEGIN
- D := Today;
- T := CurrentTime
- END;
-
- LogCDSRecord(EndedCallID);
- WriteTerminatedCallDetails({VAR} CDS,
- PasswordFailure,
- CallContinuedOn,
- CallEndedAbrupt,
- AverageCPS);
- WriteOneLineComment({VAR} CDS,Comment);
- WriteTerminatedCallDetails({VAR} SCF,
- PasswordFailure,
- CallContinuedOn,
- CallEndedAbrupt,
- AverageCPS);
- WriteOneLineComment({VAR} SCF,Comment);
-
- {Wrapup.}
- CloseCDSFiles;
- CDSIORESULT := IORESULT
- END; {LogTerminatedCall}
- {============================================================================}
-
- {============================================================================}
- PROCEDURE WrapupCommCDS;
-
- {This procedure takes care of any loose strings when the comm program is
- ready to terminate. It MUST be called as the last routine in this unit.}
-
- BEGIN {WrapupCommCDS}
- CDSIORESULT := 0;
-
- IF ActiveCall
- THEN LogTerminatedCall(FALSE,TRUE,FALSE,0,NullString);
-
- CDSIORESULT := IORESULT
- END; {WrapupCommCDS}
- {============================================================================}
-
-
- END. {CommCDS}
-