home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / COMMCDS.ZIP / COMMCDS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-01-04  |  46.9 KB  |  1,343 lines

  1. {$B-,D+,I-,R+,S+}
  2. {$O+} {so we can overlay this unit if we decide to}
  3.  
  4. UNIT CommCDS;
  5.  
  6. {
  7.            ROB ROSENBERGER               VOX: (618) 632-7345
  8.            Barn Owl Software             BBS: (618) 398-5703
  9.            P.O. Box #74                  HST: (618) 398-2305
  10.            O'Fallon, IL  62269           CIS:   74017,1344
  11.  
  12. Version 0.90 released to the public domain on 18 July 1989.
  13.    This implementation does not support querying a phone bill analyzer for $$$
  14. cost information about a call in progress.  It will be available in v1.00.
  15.  
  16.  
  17.    This Turbo Pascal 5.0 unit offers complete support for the Call Data
  18. Standard as it applies to communications software.  You can log all modem
  19. usage via simple, high-level routine calls.  These modem usage details can
  20. then be used by CDS-compatible phone bill analyzer programs to calculate
  21. the total cost of using a modem.
  22.    You can also determine the cost of a call in progress (or most recently
  23. ended) by using another simple high-level routine call.  This unit will
  24. "query" a phone bill analyzer to calculate the cost of the call for you,
  25. and you can then show this information to the user.  The effort to GET the
  26. information is a simple as a high-level routine call, but you yourself must
  27. put the information on the screen.
  28.    This unit requires the Turbo Professional 5.0 toolkit from TurboPower
  29. Software.  Write to them for a free brochure if you don't already have this
  30. powerful toolkit.  TurboPower's address is P.O. Box #66747, Scotts Valley,
  31. CA 95066-0747.
  32.    Contact Rob Rosenberger if you have any questions or comments about this
  33. unit or about the Call Data Standard.
  34.  
  35. LIMITATIONS:
  36.    CDS records 011, 012, and 013 are not implemented in this unit.  They are
  37. of an esoteric nature.  Consult the CDS specs for more information.
  38.    CDS records 040 and 045 are limited to host BBS charges.  You can modify
  39. it to work with phone company charges if you wish.}
  40.  
  41.  
  42. INTERFACE {section}
  43.  
  44. USES
  45.    DOS,
  46.    TpDOS,
  47.    TpDate,
  48.    TpString;
  49.  
  50. CONST
  51.    ProgramName : STRING[08] = 'UNKNOWN';  {your program's name, max 8 chars}
  52.    HostName    : STRING[16] = '';         {navigation programs put their host
  53.                                            service's name here.  TAPCIS, for
  54.                                            example, might use 'CompuServe'.
  55.                                            Max length is 16 chars.  Leave it
  56.                                            null if your comm program is for
  57.                                            general purpose communications.}
  58.  
  59. TYPE
  60.    CDSProtocolType
  61.      = (UnknownProtocol,
  62.         NoProtocolUsed,
  63.         ASCII,
  64.         Bimodem,
  65.         CISA,
  66.         CISB,
  67.         CISQuickB,
  68.         CISBPlus,
  69.         Jmodem,
  70.         Kermit,
  71.         Modem7,
  72.         Telink,
  73.         Xmodem,
  74.         Xmodem1K,  {sometimes mistakenly referred to as Ymodem}
  75.         Xmodem1KG,
  76.         XmodemCRC,
  77.         Ymodem,    {the true Ymodem Batch protocol}
  78.         YmodemG,   {the true Ymodem Batch protocol}
  79.         Zmodem);
  80.  
  81.    ReasonType
  82.      = (UnknownReason,
  83.         BusinessReason,
  84.         PersonalReason);
  85.  
  86.    RecordTypeRDF
  87.      = RECORD
  88.        CDSverRDF    : WORD;         {RDF version; v1.00 = 100 and so on}
  89.        ErrorValue   : BYTE;
  90.        CurrencyChar : CHAR;
  91.  
  92.        ComPort      : BYTE;
  93.        CommSpeed    : LONGINT;
  94.        DataBits     : BYTE;
  95.        Parity       : CHAR;
  96.        StopBits     : BYTE;
  97.  
  98.        CommUserName  : STRING[40];
  99.        BusinessCall  : ReasonType;
  100.        HostBBSName   : STRING[40];
  101.        PhoneNumber   : STRING[32];
  102.        EndedAbrupt   : BOOLEAN;
  103.        CallStarted   : DateTimeRec;
  104.        CallEnded     : DateTimeRec;
  105.        ElapsedTime   : Time;
  106.        AvgCPS4Call   : WORD;        {zero if unknown}
  107.        AvgEff4Call   : REAL;        {zero if unknown}
  108.        UploadXfers   : BYTE;        {sucessful uploads}
  109.        UploadAborts  : BYTE;        {aborted uploads}
  110.        DnloadXfers   : BYTE;        {successful downloads}
  111.        DnloadAborts  : BYTE;        {aborted downloads}
  112.        AvgCPS4Xfers  : WORD;        {zero if unknown}
  113.        AvgEff4Xfers  : REAL;        {zero if unknown}
  114.        PhoneCost     : REAL;
  115.        BBSCost       : REAL
  116.        END;
  117.  
  118. VAR
  119.    CDSIORESULT : BYTE;          {always contains the value of IORESULT}
  120.    RDFRecord   : RecordTypeRDF;
  121.  
  122. PROCEDURE ChangeCallParams(CommSpeed     : LONGINT;
  123.                            CommBits      : BYTE;
  124.                            CommParity    : CHAR;
  125.                            CommStopBits  : BYTE;
  126.                            CallerName    : STRING;
  127.                            HostBBSName   : STRING;
  128.                            SecurityLevel : INTEGER;
  129.                            Comment       : STRING);
  130. PROCEDURE GetCostOfCall(CDSProgName  : PathStr);
  131. PROCEDURE InitCommCDS(CDSPath : STRING);
  132. PROCEDURE LogChargeChange(Suspend : BOOLEAN;
  133.                           Comment : STRING);
  134. PROCEDURE LogFileXfer(FileName          : STRING;
  135.                       WasUploaded       : BOOLEAN;
  136.                       FileSize          : LONGINT;
  137.                       Reason4Transfer   : ReasonType;
  138.                       Protocol          : CDSProtocolType;
  139.                       SuspendBBSCharge  : BOOLEAN;
  140.                       StartingDateTime  : DateTimeRec;
  141.                       EndingDateTime    : DateTimeRec;
  142.                       AbortedBySender   : BOOLEAN;
  143.                       AbortedByRecvr    : BOOLEAN;
  144.                       CallDiedInXfer    : BOOLEAN;
  145.                       TotalXmitErrors   : WORD;
  146.                       Efficiency        : REAL;
  147.                       AverageCPS        : WORD;
  148.                       Comment           : STRING);
  149. PROCEDURE LogForumSwitch(ForumName : STRING;
  150.                          Comment   : STRING);
  151. PROCEDURE LogFreeFormatComment(CommentString : STRING);
  152. PROCEDURE LogIncomingCall(CommPort      : INTEGER;
  153.                           CommSpeed     : LONGINT;
  154.                           CommBits      : BYTE;
  155.                           CommParity    : CHAR;
  156.                           CommStopBits  : BYTE;
  157.                           CallerName    : STRING;
  158.                           SecurityLevel : INTEGER;
  159.                           LocalLogon    : BOOLEAN;
  160.                           Comment       : STRING);
  161. PROCEDURE LogOutgoingCall(CommPort     : INTEGER;
  162.                           CommSpeed    : LONGINT;
  163.                           CommBits     : BYTE;
  164.                           CommParity   : CHAR;
  165.                           CommStopBits : BYTE;
  166.                           CallerName   : STRING;
  167.                           Reason4Call  : ReasonType;
  168.                           HostBBSName  : STRING;
  169.                           PhoneNumber  : STRING;
  170.                           HostCallback : BOOLEAN;
  171.                           Comment      : STRING);
  172. PROCEDURE LogTerminatedCall(PasswordFailure : BOOLEAN;
  173.                             CallContinuedOn : BOOLEAN;
  174.                             CallEndedAbrupt : BOOLEAN;
  175.                             AverageCPS      : WORD;
  176.                             Comment         : STRING);
  177. PROCEDURE WrapupCommCDS;
  178.  
  179.  
  180. IMPLEMENTATION {section}
  181.  
  182. CONST
  183.    DirStrLen = 67;
  184.  
  185.    Colon      = ':';
  186.    Dash       = '-';
  187.    NullChar   = #0;
  188.    NullString = '';
  189.    Space      = ' ';
  190.    TabChar    = #9;
  191.  
  192.    OutgoingCallID  = 001;
  193.    HostCallbackID  = 002;
  194.    HostCallerID    = 003;
  195.    ChangeParamsID  = 008;
  196.    EndedCallID     = 009;
  197.    FileXferID      = 020;
  198.    SwitchForumID   = 030;
  199.    SuspendChargeID = 040;
  200.    ResumeChargeID  = 045;
  201.    CommentID       = 255;
  202.  
  203.    CDSext = '.CDS';
  204.    SCFext = '.SCF';
  205.    RDFext = '.RDF';
  206.  
  207.    TpDateForm = 'yy/mm/dd ';
  208.    TpTimeForm = 'hh:mm:ss ';
  209.  
  210.    MaxOneLineCommentLength = 56;
  211.  
  212. CONST {typed}
  213.    CDSProtocolIDs : ARRAY [CDSProtocolType] OF STRING[11]
  214.      = ('UNKNOWN',
  215.         'NONE',
  216.         'ASCII',
  217.         'Bimodem',
  218.         'CIS-A',
  219.         'CIS-B',
  220.         'CIS-QuickB',
  221.         'CIS-Bplus',
  222.         'Jmodem',
  223.         'Kermit',
  224.         'Modem7',
  225.         'Telink',
  226.         'Xmodem',
  227.         'Xmodem-1K',
  228.         'Xmodem-1K-G',
  229.         'Xmodem-CRC',
  230.         'Ymodem',
  231.         'Ymodem-G',
  232.         'Zmodem');
  233.  
  234.    DefaultCDSPath : DirStr = NullString;
  235.  
  236. TYPE
  237.    DirStr = STRING[DirStrLen];
  238.  
  239. VAR
  240.    CDS         : TEXT;  {the call history file}
  241.    SCF         : TEXT;  {the single call file}
  242.    RDF         : TEXT;  {the return data file}
  243.    BufferCDS   : ARRAY [1..1024] OF CHAR;
  244.    BufferSCF   : ARRAY [1..1024] OF CHAR;
  245.  
  246.    RewriteSCF   : BOOLEAN;
  247.    ActiveCall   : BOOLEAN;
  248.    OutgoingCall : BOOLEAN;
  249.  
  250.    CommentInProgress : BOOLEAN;
  251.  
  252.    CallStarted  : DateTimeRec;
  253.    CallEnded    : DateTimeRec;
  254.    CallElapsed  : Time;
  255.    XferStarted  : DateTimeRec;
  256.    XferEnded    : DateTimeRec;
  257.    XferElapsed  : Time;
  258.  
  259.    CDSStartingDateTime : DateTimeRec;
  260.  
  261.    OldTpDateSep : CHAR;
  262.    OldTpTimeSep : CHAR;
  263.  
  264.    Port     : INTEGER;
  265.    Speed    : LONGINT;
  266.    DataBits : BYTE;
  267.    Parity   : CHAR;
  268.    StopBits : BYTE;
  269.  
  270. {============================================================================}
  271. PROCEDURE CloseCDSFiles;
  272.    {This is an internal procedure.}
  273.  
  274.    {This procedure closes the CDS call history file and the CDS single call
  275. file.}
  276.  
  277. {============================================================================}
  278. PROCEDURE RestoreTpDateSeps;
  279.    {This is an internal procedure.}
  280.  
  281.    {This procedure returns TpDate to its previous settings.  Use it after a
  282. call to the ModifyTpDateSeps procedure.}
  283.  
  284. BEGIN {RestoreTpDateSeps}
  285. SlashChar := OldTpDateSep;
  286. ColonChar := OldTpTimeSep
  287. END; {RestoreTpDateSeps}
  288. {============================================================================}
  289.  
  290. BEGIN {CloseCDSFiles}
  291. CLOSE(CDS);
  292. CLOSE(SCF);
  293. RestoreTpDateSeps
  294. END; {CloseCDSFiles}
  295. {============================================================================}
  296.  
  297. {============================================================================}
  298. PROCEDURE LogCDSRecord(RecordValue : BYTE);
  299.    {This is an internal procedure.}
  300.  
  301.    {This procedure logs the master record identifier for a given CDS entry.}
  302.  
  303. {============================================================================}
  304. PROCEDURE WriteCDSRecord(VAR F : TEXT);
  305.    {This is an internal procedure.}
  306.  
  307.    {This procedure writes the actual CDS record.  It is a routine in its own
  308. right because the same record will be written to multiple CDS files.}
  309.  
  310. BEGIN {WriteCDSRecord}
  311. WRITELN(F);
  312. WRITE(F,DateToDateString(TpDateForm,CDSStartingDateTime.D),
  313.           TimeToTimeString(TpTimeForm,CDSStartingDateTime.T));
  314. CASE RecordValue OF
  315.   0..9   : WRITE(F,'00',RecordValue,Space);
  316.   10..99 : WRITE(F,'0',RecordValue,Space);
  317.   ELSE     WRITE(F,RecordValue,Space)
  318.  END; {CASE}
  319. WRITELN(F,ProgramName);
  320.  
  321. IF ((RecordValue <> CommentID) OR ((RecordValue = CommentID) AND ActiveCall))
  322.  THEN WRITELN(F,TabChar,'COM port ',Port)
  323. END; {WriteCDSRecord}
  324. {============================================================================}
  325.  
  326. BEGIN {LogCDSRecord}
  327. {Initialize.}
  328. IF (CDSStartingDateTime.D = BadDate)
  329.  THEN {use the current date & time}
  330.     WITH CDSStartingDateTime
  331.      DO BEGIN
  332.         D := Today;
  333.         T := CurrentTime
  334.         END;
  335.  {ELSE use the supplied date & time}
  336.  
  337. WriteCDSRecord({VAR} CDS);
  338. WriteCDSRecord({VAR} SCF);
  339.  
  340. {Wrapup.}
  341. CDSStartingDateTime.D := BadDate
  342. END; {LogCDSRecord}
  343. {============================================================================}
  344.  
  345. {============================================================================}
  346. PROCEDURE OpenCDSFiles;
  347.    {This is an internal procedure.}
  348.  
  349.    {This procedure opens the CDS call history file and the CDS single call
  350. file for output.}
  351.  
  352. {============================================================================}
  353. PROCEDURE ModifyTpDateSeps;
  354.    {This is an internal procedure.}
  355.  
  356.    {This procedure adjusts TpDate to CDS needs.  Use the RestoreTpDateSeps
  357. procedure before returning control to the comm program.}
  358.  
  359. BEGIN {ModifyTpDateSeps}
  360. OldTpDateSep := SlashChar;
  361. OldTpTimeSep := ColonChar;
  362.  
  363. SlashChar := Dash;
  364. ColonChar := Colon
  365. END; {ModifyTpDateSeps}
  366. {============================================================================}
  367.  
  368. BEGIN {OpenCDSFiles}
  369. IF ExistFile(DefaultCDSPath + ProgramName + CDSext)
  370.  THEN APPEND(CDS)
  371.  ELSE REWRITE(CDS);
  372.  
  373. IF RewriteSCF
  374.  THEN
  375.     BEGIN
  376.     REWRITE(SCF);
  377.     RewriteSCF := FALSE
  378.     END
  379.  ELSE
  380.     APPEND(SCF);
  381.  
  382. SETTEXTBUF(CDS,BufferCDS);
  383. SETTEXTBUF(SCF,BufferSCF);
  384.  
  385. ModifyTpDateSeps
  386. END; {OpenCDSFiles}
  387. {============================================================================}
  388.  
  389. {============================================================================}
  390. PROCEDURE WriteCommDetails(VAR F : TEXT);
  391.    {This is an internal procedure.}
  392.  
  393.    {This procedure writes comm speed/parity/stop bit details about the call.
  394. It is a procedure in its own right because the details must be logged in
  395. multiple CDS files.  It is up to the calling routine to check IORESULT.}
  396.  
  397. BEGIN {WriteCommDetails}
  398. WRITELN(F,TabChar,'Comm parameters ',
  399.           Speed,Space,DataBits,Space,Parity,Space,StopBits);
  400. END; {WriteCommDetails}
  401. {============================================================================}
  402.  
  403. {============================================================================}
  404. PROCEDURE WriteFileXferDetails(VAR F                : TEXT;
  405.                                    FileName         : STRING;
  406.                                    WasUploaded      : BOOLEAN;
  407.                                    FileSize         : LONGINT;
  408.                                    Reason4Transfer  : ReasonType;
  409.                                    Protocol         : CDSProtocolType;
  410.                                    SuspendBBSCharge : BOOLEAN;
  411.                                    EndingDateTime   : DateTimeRec;
  412.                                    AbortedBySender  : BOOLEAN;
  413.                                    AbortedByRecvr   : BOOLEAN;
  414.                                    CallDiedInXfer   : BOOLEAN;
  415.                                    TotalXmitErrors  : WORD;
  416.                                    Efficiency       : REAL;
  417.                                    AverageCPS       : WORD);
  418.    {This is an internal procedure.}
  419.  
  420.    {This procedure writes specific CDS details about a file transfer.  It is
  421. a procedure in its own right because these details must be logged in multiple
  422. CDS files.}
  423.  
  424. VAR
  425.    Days : WORD;
  426.    Secs : LONGINT;
  427.  
  428.    Hours   : BYTE;
  429.    Minutes : BYTE;
  430.    Seconds : BYTE;
  431.  
  432. BEGIN {WriteFileXferDetails}
  433. {Initialize.}
  434. Filename := StUpCase(JustFilename(Filename));
  435.  
  436. WriteCommDetails({VAR} F);
  437.  
  438. IF WasUploaded
  439.  THEN WRITELN(F,TabChar,'Sent file ',Filename)
  440.  ELSE WRITELN(F,TabChar,'Rcvd file ',Filename);
  441.  
  442. WRITELN(F,TabChar,'File size ',FileSize);
  443.  
  444. IF (Reason4Transfer = UnknownReason)
  445.  THEN
  446.     {Do nothing.}
  447.  ELSE
  448.     BEGIN
  449.     IF (Reason4Transfer = BusinessReason)
  450.      THEN WRITE(F,TabChar,'Business ')
  451.      ELSE WRITE(F,TabChar,'Personal ');
  452.     WRITELN(F,' file transfer')
  453.     END;
  454.  
  455. WRITELN(F,TabChar,'Protocol ',CDSProtocolIDs[Protocol]);
  456.  
  457. IF SuspendBBSCharge
  458.  THEN
  459.     BEGIN
  460.     WRITE(F,TabChar,'Suspend host charges');
  461.     IF (Hostname = NullString)
  462.      THEN WRITELN(F)
  463.      ELSE WRITELN(F,' (',Hostname,')')
  464.     END;
  465.  
  466. WRITE(F,TabChar,
  467.         'Ended ',
  468.         DateToDateString(TpDateForm,EndingDateTime.D),
  469.         TimeToTimeString(TpTimeForm,EndingDateTime.T));
  470. IF AbortedBySender
  471.  THEN
  472.     WRITELN(F,' (aborted by sender)')
  473.  ELSE
  474.     IF AbortedByRecvr
  475.      THEN
  476.         WRITELN(F,' (aborted by receiver)')
  477.      ELSE
  478.         IF CallDiedInXfer
  479.          THEN
  480.             WRITELN(F,' (call ended abruptly)')
  481.          ELSE
  482.             WRITELN(F);
  483.  
  484. DateTimeDiff(XferStarted,XferEnded,{VAR} Days,{VAR} Secs);
  485. TimeToHMS(Secs,{VAR} Hours,{VAR} Minutes,{VAR} Seconds);
  486. INC(Hours,(Days * HoursInDay));
  487. IF (Hours < 10)
  488.  THEN WRITE(F,TabChar,'Elapsed time ','0',Hours,Colon)
  489.  ELSE WRITE(F,TabChar,'Elapsed time ',Hours,Colon);
  490. IF (Minutes < 10)
  491.  THEN WRITE(F,'0',Minutes,Colon)
  492.  ELSE WRITE(F,Minutes,Colon);
  493. IF (Seconds < 10)
  494.  THEN WRITELN(F,'0',Seconds)
  495.  ELSE WRITELN(F,Seconds);
  496.  
  497. IF (TotalXmitErrors > 0)
  498.  THEN WRITELN(F,TabChar,'Transfer Errors ',TotalXmitErrors);
  499.  
  500. IF (Efficiency > 0)
  501.  THEN WRITELN(F,TabChar,'Efficiency ',Efficiency:1:1,' %');
  502.  
  503. IF (AverageCPS > 0)
  504.  THEN WRITELN(F,TabChar,'Average CPS ',AverageCPS)
  505. END; {WriteFileXferDetails}
  506. {============================================================================}
  507.  
  508. {============================================================================}
  509. PROCEDURE WriteFirstCommentLine(VAR F : TEXT);
  510.    {This is an internal procedure.}
  511.  
  512.    {This procedure writes the first comment line of a multi-line free-format
  513. comment.}
  514.  
  515. BEGIN {WriteFirstCommentLine}
  516. WRITELN(F,TabChar,'COMMENT: ')
  517. END; {WriteFirstCommentLine}
  518. {============================================================================}
  519.  
  520. {============================================================================}
  521. PROCEDURE WriteForumSwitchDetails(VAR F         : TEXT;
  522.                                       ForumName : STRING);
  523.    {This is an internal procedure.}
  524.  
  525.    {This procedure writes specific CDS details about a user who is switching
  526. between forums of a host system.}
  527.  
  528. BEGIN {WriteForumSwitchDetails}
  529. IF (ForumName = NullString)
  530.  THEN EXIT; {no need to hang around, eh?}
  531. IF (LENGTH(ForumName) > 16)
  532.  THEN ForumName[0] := #16;
  533.  
  534. WRITELN(F,TabChar,'Moved to forum ',ForumName)
  535. END; {WriteForumSwitchDetails}
  536. {============================================================================}
  537.  
  538. {============================================================================}
  539. PROCEDURE WriteFreeFormatComment(VAR F       : TEXT;
  540.                                      Comment : STRING);
  541.    {This is an internal procedure.}
  542.  
  543.    {This procedure writes a free-format comment to the given CDS file.  It
  544. performs word-wrapping for the comment string, if necessary.  It does NOT
  545. truncate the string.}
  546.  
  547. CONST
  548.    CommentMargin = 65;
  549.  
  550. VAR
  551.    OutString : STRING;
  552.    Overlap   : STRING;
  553.  
  554. BEGIN {WriteFreeFormatComment}
  555. REPEAT
  556.     WordWrap(Comment,
  557.        {VAR} OutString,
  558.        {VAR} Comment,
  559.              CommentMargin,
  560.              FALSE); {no padding desired}
  561.     WRITELN(F,TabChar,OutString);
  562.  UNTIL (Comment = NullString);
  563. END; {WriteFreeFormatComment}
  564. {============================================================================}
  565.  
  566. {============================================================================}
  567. PROCEDURE WriteIncomingCallDetails(VAR F             : TEXT;
  568.                                        CallerName    : STRING;
  569.                                        SecurityLevel : INTEGER;
  570.                                        LocalLogon    : BOOLEAN);
  571.    {This is an internal procedure.}
  572.  
  573.    {This procedure writes specific CDS details about an incoming call.  It is
  574. a procedure in its own right because these details must be logged in multiple
  575. CDS files.}
  576.  
  577. BEGIN {WriteIncomingCallDetails}
  578. WriteCommDetails({VAR} F);
  579.  
  580. IF (CallerName = NullString)
  581.  THEN
  582.     {Do nothing.}
  583.  ELSE
  584.     BEGIN
  585.     IF (LENGTH(CallerName) > 40)
  586.      THEN CallerName[0] := #40;
  587.     WRITELN(F,TabChar,'Connected with ',CallerName)
  588.     END;
  589.  
  590. IF LocalLogon
  591.  THEN WRITELN(F,TabChar,'Local logon');
  592.  
  593. WRITELN(F,TabChar,'Security level ',SecurityLevel)
  594. END; {WriteIncomingCallDetails}
  595. {============================================================================}
  596.  
  597. {============================================================================}
  598. PROCEDURE WriteOneLineComment(VAR F       : TEXT;
  599.                                   Comment : STRING);
  600.    {This is an internal procedure.}
  601.  
  602.    {This procedure writes a one-line comment if it is provided.  Comments are
  603. truncated if they exceed the maximum allowable length.}
  604.  
  605. BEGIN {WriteOneLineComment}
  606. IF (Comment = NullString)
  607.  THEN EXIT; {no need to hang around here}
  608.  
  609. IF (LENGTH(Comment) > MaxOneLineCommentLength)
  610.  THEN Comment[0] := CHR(MaxOneLineCommentLength);
  611.  
  612. WRITELN(F,TabChar,'Comment: ',Comment)
  613. END; {WriteOneLineComment}
  614. {============================================================================}
  615.  
  616. {============================================================================}
  617. PROCEDURE WriteOutgoingCallDetails(VAR F           : TEXT;
  618.                                        CallerName  : STRING;
  619.                                        Reason4Call : ReasonType;
  620.                                        HostBBSName : STRING;
  621.                                        PhoneNumber : STRING;
  622.                                        IgnorePhNbr : BOOLEAN);
  623.    {This is an internal procedure.}
  624.  
  625.    {This procedure writes specific CDS details about an outgoing call.  It is
  626. a procedure in its own right because these details must be logged in multiple
  627. CDS files.}
  628.  
  629. BEGIN {WriteOutgoingCallDetails}
  630. WriteCommDetails({VAR} F);
  631.  
  632. IF (CallerName = NullString)
  633.  THEN
  634.     {Do nothing.}
  635.  ELSE
  636.     BEGIN
  637.     IF (LENGTH(CallerName) > 40)
  638.      THEN CallerName[0] := #40;
  639.     WRITELN(F,TabChar,'Caller was ',CallerName)
  640.     END;
  641.  
  642. IF (Reason4Call = UnknownReason)
  643.  THEN
  644.     {Do nothing.}
  645.  ELSE
  646.     BEGIN
  647.     IF (Reason4Call = BusinessReason)
  648.      THEN WRITE(F,TabChar,'Business ')
  649.      ELSE WRITE(F,TabChar,'Personal ');
  650.     WRITELN(F,' call')
  651.     END;
  652.  
  653. IF (HostBBSName = NullString)
  654.  THEN
  655.     {Do nothing.}
  656.  ELSE
  657.     BEGIN
  658.     IF (LENGTH(HostBBSName) > 40)
  659.      THEN HostBBSName[0] := #40;
  660.     WRITELN(F,TabChar,'Connected with ',HostBBSName)
  661.     END;
  662.  
  663. IF (PhoneNumber = NullString)
  664.  THEN
  665.     IF IgnorePhNbr
  666.      THEN {null}
  667.      ELSE WRITELN(F,TabChar,'CALL WAS ALREADY IN PROGRESS')
  668.  ELSE
  669.     BEGIN
  670.     IF (LENGTH(PhoneNumber) > 32)
  671.      THEN PhoneNumber[0] := #32;
  672.     WRITELN(F,TabChar,'Phone number ',PhoneNumber)
  673.     END
  674. END; {WriteOutgoingCallDetails}
  675. {============================================================================}
  676.  
  677. {============================================================================}
  678. PROCEDURE WriteChargeDetails(VAR F       : TEXT;
  679.                                  Suspend : BOOLEAN;
  680.                                  HostBBS : BOOLEAN;
  681.                                  PhoneCo : BOOLEAN);
  682.    {This is an internal procedure.}
  683.  
  684.    {This procedure writes specific CDS details about suspending or resuming
  685. phone company or host BBS charges.}
  686.  
  687. VAR
  688.    TheText : STRING[7];
  689.  
  690. BEGIN {WriteResumeChargeDetails}
  691. IF Suspend
  692.  THEN TheText := 'Suspend'
  693.  ELSE TheText := 'Resume';
  694.  
  695. IF HostBBS
  696.  THEN
  697.     BEGIN
  698.     WRITE(F,TabChar,TheText,' host charges');
  699.     IF (HostName = NullString)
  700.      THEN WRITELN(F)
  701.      ELSE WRITELN(F,' (',HostName,')')
  702.     END;
  703.  
  704. IF PhoneCo
  705.  THEN WRITELN(F,TabChar,TheText,' phone charges')
  706. END; {WriteResumeChargeDetails}
  707. {============================================================================}
  708.  
  709. {============================================================================}
  710. PROCEDURE WriteTerminatedCallDetails(VAR F               : TEXT;
  711.                                          PasswordFailure : BOOLEAN;
  712.                                          CallContinuedOn : BOOLEAN;
  713.                                          CallEndedAbrupt : BOOLEAN;
  714.                                          AverageCPS      : WORD);
  715.    {This is an internal procedure.}
  716.  
  717.    {This procedure writes specific CDS details about a terminated call.  It is
  718. a procedure in its own right because these details must be logged in multiple
  719. CDS files.}
  720.  
  721. VAR
  722.    Days : WORD;
  723.    Secs : LONGINT;
  724.  
  725.    Hours   : BYTE;
  726.    Minutes : BYTE;
  727.    Seconds : BYTE;
  728.  
  729. BEGIN {WriteTerminatedCallDetails}
  730. IF PasswordFailure
  731.  THEN WRITELN(F,TabChar,'FAILED TO PROVIDE PASSWORD');
  732.  
  733. IF CallContinuedOn
  734.  THEN
  735.     WRITELN(F,TabChar,'CALL REMAINED IN PROGRESS')
  736.  ELSE
  737.     IF CallEndedAbrupt
  738.      THEN WRITELN(F,TabChar,'Call ended abruptly');
  739.  
  740. DateTimeDiff(CallStarted,CallEnded,{VAR} Days,{VAR} Secs);
  741. TimeToHMS(Secs,{VAR} Hours,{VAR} Minutes,{VAR} Seconds);
  742. INC(Hours,(Days * HoursInDay));
  743. IF (Hours < 10)
  744.  THEN WRITE(F,TabChar,'Elapsed time ','0',Hours,Colon)
  745.  ELSE WRITE(F,TabChar,'Elapsed time ',Hours,Colon);
  746. IF (Minutes < 10)
  747.  THEN WRITE(F,'0',Minutes,Colon)
  748.  ELSE WRITE(F,Minutes,Colon);
  749. IF (Seconds < 10)
  750.  THEN WRITELN(F,'0',Seconds)
  751.  ELSE WRITELN(F,Seconds);
  752.  
  753. IF (AverageCPS > 0)
  754.  THEN WRITELN(F,TabChar,'Average CPS ',AverageCPS)
  755. END; {WriteTerminatedCallDetails}
  756. {============================================================================}
  757.  
  758.  
  759. {- - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - - - - - - - - -}
  760.  
  761.  
  762. {============================================================================}
  763. PROCEDURE ChangeCallParams(CommSpeed     : LONGINT;
  764.                            CommBits      : BYTE;
  765.                            CommParity    : CHAR;
  766.                            CommStopBits  : BYTE;
  767.                            CallerName    : STRING;
  768.                            HostBBSName   : STRING;
  769.                            SecurityLevel : INTEGER;
  770.                            Comment       : STRING);
  771.  
  772.    {This procedure lets you change the OPTIONAL details of a call which is
  773. already in progress.
  774.    CommSpeed, CommBits, CommParity, and CommStopBits must always be supplied
  775. with their proper values when invoking this routine.
  776.    CallerName and HostBBSName are written out to the CDS files only if they
  777. contain data.  Null strings are ignored.
  778.    SecurityLevel is written out in all cases where the call was taken by the
  779. host mode.  This unit knows when an active call is a host call (including any
  780. call which is a security host callback).
  781.    Comment is any text you wish to add to the CDS record.  It is truncated if
  782. it exceeds the maximum allowable length.}
  783.  
  784. BEGIN {ChangeCallParams}
  785. {Initialize.}
  786. CDSIORESULT := 0;
  787. OpenCDSFiles;
  788.  
  789. Speed    := CommSpeed;
  790. DataBits := CommBits;
  791. Parity   := CommParity;
  792. StopBits := CommStopBits;
  793.  
  794. LogCDSRecord(ChangeParamsID);
  795. IF OutgoingCall
  796.  THEN
  797.     BEGIN
  798.     WriteOutgoingCallDetails({VAR} CDS,
  799.                                    CallerName,
  800.                                    UnknownReason, {don't touch call reason}
  801.                                    HostBBSName,
  802.                                    NullString,
  803.                                    TRUE);
  804.     WriteOutgoingCallDetails({VAR} SCF,
  805.                                    CallerName,
  806.                                    UnknownReason, {don't touch call reason}
  807.                                    HostBBSName,
  808.                                    NullString,
  809.                                    TRUE)
  810.     END
  811.  ELSE
  812.     BEGIN
  813.     WriteIncomingCallDetails({VAR} CDS,
  814.                                    CallerName,
  815.                                    SecurityLevel,
  816.                                    FALSE);
  817.     WriteIncomingCallDetails({VAR} SCF,
  818.                                    CallerName,
  819.                                    SecurityLevel,
  820.                                    FALSE)
  821.     END;
  822. WriteOneLineComment({VAR} CDS,Comment);
  823. WriteOneLineComment({VAR} SCF,Comment);
  824.  
  825. {Wrapup.}
  826. CloseCDSFiles;
  827. CDSIORESULT := IORESULT
  828.  
  829. END; {ChangeCallParams}
  830. {============================================================================}
  831.  
  832. {============================================================================}
  833. PROCEDURE GetCostOfCall(CDSProgName  : PathStr);
  834.  
  835.    {This procedure queries the CDS program defined in CDSProgName for the cost
  836. of the call defined in the SCF file.  This procedure can be called any time,
  837. even if the call is still in progress.
  838.  
  839.    ErrorValue returns with a zero to indicate success.  Any other value is a
  840. failure; all other fields are undefined.  Current ErrorValue codes:
  841.          0 -- Success
  842.          1 -- PRF file was invalid or not found
  843.          2 -- PRF file complies to unknown CDS standard
  844.          3 -- error dealing with the SCF file
  845.          4 -- not enough memory for phone bill analyzer
  846.        255 -- phone bill analyzer aborted
  847.  
  848. You must still check CDSIORESULT after calling this procedure.  Checking the
  849. ErrorValue is not enough.}
  850.  
  851. BEGIN {GetCostOfCall}
  852. {Initialize.}
  853. ASSIGN(RDF,(DefaultCDSPath + ProgramName + RDFext));
  854. ERASE(RDF);
  855. FILLCHAR(RDFRecord,SIZEOF(RDFRecord),NullChar);
  856.  
  857. {Execute the CDS phone bill analyzer.}
  858. CDSIORESULT := ExecDOS((CDSProgName + ' /CDS'
  859.                             + DefaultCDSPath + ProgramName + SCFext
  860.                             + ','
  861.                             + DefaultCDSPath + ProgramName + RDFext),
  862.                        TRUE,NIL);
  863.  
  864. {Did we get back a CDS RDF file?}
  865. IF ExistFile(DefaultCDSPath + ProgramName + RDFext)
  866.  THEN
  867.  
  868.  ELSE
  869.     BEGIN
  870.     {Read the CDS RDF file.}
  871.     RESET(RDF);
  872.  
  873.     END
  874. END; {GetCostOfCall}
  875. {============================================================================}
  876.  
  877. {============================================================================}
  878. PROCEDURE InitCommCDS(CDSPath : STRING);
  879.  
  880.    {This procedure initializes the CommCDS unit.  It MUST be called before
  881. any other routine in this unit.
  882.    CDSPath specifies a path for all CDS files.  Set this to a null string for
  883. the default drive & directory.}
  884.  
  885. BEGIN {InitCommCDS}
  886. CDSIORESULT    := 0;
  887. DefaultCDSPath := AddBackslash(CDSPath);
  888.  
  889. ASSIGN(CDS,(DefaultCDSPath + ProgramName + CDSext));
  890. ASSIGN(SCF,(DefaultCDSPath + ProgramName + SCFext));
  891.  
  892. RewriteSCF := TRUE;
  893. ActiveCall := FALSE;
  894.  
  895. CommentInProgress := FALSE;
  896.  
  897. CDSStartingDateTime.D := BadDate
  898. END; {InitCommCDS}
  899. {============================================================================}
  900.  
  901. {============================================================================}
  902. PROCEDURE LogChargeChange(Suspend : BOOLEAN;
  903.                           Comment : STRING);
  904.  
  905.    {This procedure suspends or resumes host BBS or phone company charges, as
  906. reflected in the CDS files.  It specifically overrides any assumptions made by
  907. phone bill analyzers about charges for the call.  This is extremely handy in
  908. navigation software like TAPCIS when uploading.  CompuServe suspends charges
  909. during an upload, and continues suspending charges while the user types in a
  910. description for the file.  TAPCIS could therefore show exactly when charges
  911. were suspended and when they finally resumed again.
  912.    Suspend dictates whether charges are being suspended or resumed.
  913.    HostBBS dictates whether this applies to host charges.
  914.    PhoneCo dictates whether this applies to phone company charges.
  915.    Comment is any text you wish to add to the CDS record.  It is truncated if
  916. it exceeds the maximum allowable length.}
  917.  
  918. BEGIN {LogChargeChange}
  919. {Initialize.}
  920. CDSIORESULT := 0;
  921. OpenCDSFiles;
  922.  
  923. IF Suspend
  924.  THEN LogCDSRecord(SuspendChargeID)
  925.  ELSE LogCDSRecord(ResumeChargeID);
  926. WriteChargeDetails({VAR} CDS,Suspend,TRUE,FALSE);
  927. WriteOneLineComment({VAR} CDS,Comment);
  928. WriteChargeDetails({VAR} SCF,Suspend,TRUE,FALSE);
  929. WriteOneLineComment({VAR} SCF,Comment);
  930.  
  931. {Wrapup.}
  932. CloseCDSFiles;
  933. CDSIORESULT := IORESULT
  934. END; {LogChargeChange}
  935. {============================================================================}
  936.  
  937. {============================================================================}
  938. PROCEDURE LogFileXfer(FileName          : STRING;
  939.                       WasUploaded       : BOOLEAN;
  940.                       FileSize          : LONGINT;
  941.                       Reason4Transfer   : ReasonType;
  942.                       Protocol          : CDSProtocolType;
  943.                       SuspendBBSCharge  : BOOLEAN;
  944.                       StartingDateTime  : DateTimeRec;
  945.                       EndingDateTime    : DateTimeRec;
  946.                       AbortedBySender   : BOOLEAN;
  947.                       AbortedByRecvr    : BOOLEAN;
  948.                       CallDiedInXfer    : BOOLEAN;
  949.                       TotalXmitErrors   : WORD;
  950.                       Efficiency        : REAL;
  951.                       AverageCPS        : WORD;
  952.                       Comment           : STRING);
  953.  
  954.   {The modem's speed, parity, and stop bits are assumed to be the same as they
  955. were previously.  The comm program must invoke ChangeCallParams if it wants to
  956. use a different setting for these values.
  957.    Filename is the name of the file being transferred.  This procedure will
  958. remove the drive & path from any filename you send it.
  959.    WasUploaded dictates if the file was uploaded or downloaded.
  960.    FileSize is the size of the transferred file.
  961.    Reason4Transfer dictates whether this transfer took place for business
  962. reasons, for personal reasons, or for unknown reasons.
  963.    Protocol is the CDS protocol used for the file transfer.
  964.    SuspendBBSCharge dictates whether the host computer is suspending charges
  965. during this file transfer.
  966.    Starting/EndingDate/Time denote the date/time the transfer started/ended.
  967.    AbortedBySender is TRUE only if the uploader aborted the transfer.
  968.    AbortedByRecvr is TRUE only if the downloader aborted the transfer.
  969.    CallDiedInXfer is TRUE only if the call terminated abruptly during the file
  970. transfer.
  971.    TotalXmitErrors designates the number of bad blocks that appeared during
  972. the transfer.
  973.    Efficiency is the relative efficiency of the transfer.  This number appears
  974. in CDS files with an accuracy of at least 0.1, but of course the accuracy is
  975. strictly up to you.  A 97.2% efficiency would be stored in this variable as
  976. 97.2.  The value is left out of the CDS activity log entirely if you supply a
  977. value of 0.0.
  978.    AverageCPS is the average chars per second for the overall transfer.  It is
  979. left out of the CDS activity log entirely if you supply a valud of 0.
  980.    Comment is any text you wish to add to the CDS record.  It is truncated if
  981. it exceeds the maximum allowable length.}
  982.  
  983. BEGIN {LogFileXfer}
  984. {Initialize.}
  985. CDSIORESULT := 0;
  986. OpenCDSFiles;
  987. XferStarted := StartingDateTime;
  988. XferEnded   := EndingDateTime;
  989.  
  990. CDSStartingDateTime := StartingDateTime;
  991. LogCDSRecord(FileXferID);
  992. WriteFileXferDetails({VAR} CDS,
  993.                            FileName,
  994.                            WasUploaded,
  995.                            FileSize,
  996.                            Reason4Transfer,
  997.                            Protocol,
  998.                            SuspendBBSCharge,
  999.                            EndingDateTime,
  1000.                            AbortedBySender,
  1001.                            AbortedByRecvr,
  1002.                            CallDiedInXfer,
  1003.                            TotalXmitErrors,
  1004.                            Efficiency,
  1005.                            AverageCPS);
  1006. WriteOneLineComment({VAR} CDS,Comment);
  1007. WriteFileXferDetails({VAR} SCF,
  1008.                            FileName,
  1009.                            WasUploaded,
  1010.                            FileSize,
  1011.                            Reason4Transfer,
  1012.                            Protocol,
  1013.                            SuspendBBSCharge,
  1014.                            EndingDateTime,
  1015.                            AbortedBySender,
  1016.                            AbortedByRecvr,
  1017.                            CallDiedInXfer,
  1018.                            TotalXmitErrors,
  1019.                            Efficiency,
  1020.                            AverageCPS);
  1021. WriteOneLineComment({VAR} SCF,Comment);
  1022.  
  1023. {Wrapup.}
  1024. CloseCDSFiles;
  1025. CDSIORESULT := IORESULT
  1026. END; {LogFileXfer}
  1027. {============================================================================}
  1028.  
  1029. {============================================================================}
  1030. PROCEDURE LogForumSwitch(ForumName : STRING;
  1031.                          Comment   : STRING);
  1032.  
  1033.    {This procedure logs a switch between various forums, or conference areas,
  1034. of a host computer system.  This includes when the comm program is [acting as]
  1035. a BBS.
  1036.    ForumName is the name of the new forum.  It will be truncated if it exceeds
  1037. 16 chars.  Note: CDS phone bill analyzers automatically assume the first forum
  1038. is an "overhead" which encompasses the logon procedure.  You would be wise to
  1039. log that you switched to the "main" forum (or whatever) when you reach a known
  1040. landmark in the host system.
  1041.    Comment is any text you wish to add to the CDS record.  It is truncated if
  1042. it exceeds the maximum allowable length.}
  1043.  
  1044. BEGIN {LogForumSwitch}
  1045. {Initialize.}
  1046. CDSIORESULT := 0;
  1047. OpenCDSFiles;
  1048.  
  1049. LogCDSRecord(SwitchForumID);
  1050. WriteForumSwitchDetails({VAR} CDS,ForumName);
  1051. WriteOneLineComment({VAR} CDS,Comment);
  1052. WriteForumSwitchDetails({VAR} SCF,ForumName);
  1053. WriteOneLineComment({VAR} SCF,Comment);
  1054.  
  1055. {Wrapup.}
  1056. CloseCDSFiles;
  1057. CDSIORESULT := IORESULT
  1058. END; {LogForumSwitch}
  1059. {============================================================================}
  1060.  
  1061. {============================================================================}
  1062. PROCEDURE LogFreeFormatComment(CommentString : STRING);
  1063.  
  1064.    {This procedure adds a free-format comment to the CDS log.}
  1065.  
  1066.    {NOTE: This procedure works different from all other procedures.  There is
  1067. only one CommentString variable -- however, you may call this procedure as
  1068. many times as it takes to send your entire comment down the line.  The only
  1069. requirement is that you MUST end the comment by calling this procedure with
  1070. a null string as the CommentString.  This signals you are finished with your
  1071. free-format comment.
  1072.    CDSIORESULT is NOT initialized until a comment has been ended.  Check the
  1073. value *after* you call this procedure with a null string.
  1074.    The CommentString can be any length you want.  Word-wrapping is performed
  1075. as necessary to make the string fit within CDS constraints.  A CR/LF is added
  1076. to the end of each CommentString.  Please be aware of this if you want to use
  1077. special formatting for each string.
  1078.    Comments are automatically 'tied' to a phone call if a call is in progress.
  1079. Otherwise they are considered 'generic', or global, comments in the CDS log.}
  1080.  
  1081. BEGIN {LogFreeFormatComment}
  1082. {Initialize.}
  1083. CDSIORESULT := 0;
  1084. OpenCDSFiles;
  1085.  
  1086. IF (CommentString = NullString)
  1087.  THEN
  1088.     CommentInProgress := FALSE
  1089.  ELSE
  1090.     BEGIN
  1091.     IF CommentInProgress
  1092.      THEN
  1093.         {Do nothing.}
  1094.      ELSE
  1095.         BEGIN
  1096.         {Begin a comment in the CDS logs.}
  1097.         CDSStartingDateTime.D := BadDate;
  1098.         LogCDSRecord(CommentID);
  1099.  
  1100.         WriteFirstCommentLine({VAR} CDS);
  1101.         WriteFirstCommentLine({VAR} SCF);
  1102.         CommentInProgress := TRUE
  1103.         END;
  1104.  
  1105.     WriteFreeFormatComment({VAR} CDS,CommentString);
  1106.     WriteFreeFormatComment({VAR} SCF,CommentString);
  1107.     END;
  1108.  
  1109. {Wrapup ONLY if the comment is complete.}
  1110. IF CommentInProgress
  1111.  THEN
  1112.     {Do nothing.}
  1113.  ELSE
  1114.     BEGIN
  1115.     CloseCDSFiles;
  1116.     CDSIORESULT := IORESULT
  1117.     END
  1118. END; {LogFreeFormatComment}
  1119. {============================================================================}
  1120.  
  1121. {============================================================================}
  1122. PROCEDURE LogIncomingCall(CommPort      : INTEGER;
  1123.                           CommSpeed     : LONGINT;
  1124.                           CommBits      : BYTE;
  1125.                           CommParity    : CHAR;
  1126.                           CommStopBits  : BYTE;
  1127.                           CallerName    : STRING;
  1128.                           SecurityLevel : INTEGER;
  1129.                           LocalLogon    : BOOLEAN;
  1130.                           Comment       : STRING);
  1131.  
  1132.    {This procedure logs an incoming call.}
  1133.  
  1134.    {CallerName is the name of the person who called.  You should determine who
  1135. the caller is before you invoke this routine.  Use 'UNKNOWN' (all caps) if the
  1136. caller hangs up before giving a name.  Use 'SYSOP' (all caps) if the sysop is
  1137. logging in.  CallerName is truncated if it exceeds 40 chars.
  1138.    SecurityLevel is the security access authorized for the caller.  It can be
  1139. a negative number if you use them as access levels.
  1140.    LocalLogon is TRUE if the logon is occuring at the local site.  This is a
  1141. common occurance when sysops log in, for example.
  1142.    Comment is any text you wish to add to the CDS record.  It is truncated if
  1143. it exceeds the maximum allowable lenght.}
  1144.  
  1145. BEGIN {LogIncomingCall}
  1146. {Initialize.}
  1147. CDSIORESULT := 0;
  1148. OpenCDSFiles;
  1149.  
  1150. {Set up the call in progress.}
  1151. RewriteSCF   := TRUE;
  1152. ActiveCall   := TRUE;
  1153. OutgoingCall := FALSE;
  1154.  
  1155. Port     := CommPort;
  1156. Speed    := CommSpeed;
  1157. DataBits := CommBits;
  1158. Parity   := CommParity;
  1159. StopBits := CommStopBits;
  1160.  
  1161. CDSStartingDateTime := CallStarted;
  1162. LogCDSRecord(HostCallerID);
  1163. WriteIncomingCallDetails({VAR} CDS,
  1164.                                CallerName,
  1165.                                SecurityLevel,
  1166.                                LocalLogon);
  1167. WriteOneLineComment({VAR} CDS,Comment);
  1168. WriteIncomingCallDetails({VAR} SCF,
  1169.                                CallerName,
  1170.                                SecurityLevel,
  1171.                                LocalLogon);
  1172. WriteOneLineComment({VAR} SCF,Comment);
  1173.  
  1174. {Wrapup.}
  1175. CloseCDSFiles;
  1176. CDSIORESULT := IORESULT
  1177. END; {LogIncomingCall}
  1178. {============================================================================}
  1179.  
  1180. {============================================================================}
  1181. PROCEDURE LogOutgoingCall(CommPort     : INTEGER;
  1182.                           CommSpeed    : LONGINT;
  1183.                           CommBits     : BYTE;
  1184.                           CommParity   : CHAR;
  1185.                           CommStopBits : BYTE;
  1186.                           CallerName   : STRING;
  1187.                           Reason4Call  : ReasonType;
  1188.                           HostBBSName  : STRING;
  1189.                           PhoneNumber  : STRING;
  1190.                           HostCallback : BOOLEAN;
  1191.                           Comment      : STRING);
  1192.  
  1193.    {This procedure logs an outgoing call.  It assumes the starting date/time
  1194. of the call is RIGHT NOW.  You should log a call the instant you detect it.
  1195.  
  1196.    CallerName is normally a null string, except in cases like TAPCIS where it
  1197. should be filled with the userID of the person calling.  Some programs, such
  1198. as QMODEM, accept the person's name as part of the registration process, and
  1199. therefore might want to use that as the CallerName.  CallerName is truncated
  1200. if it exceeds 40 chars.
  1201.    HostBBSName is usually known, but there are exceptions.  You won't know the
  1202. name of a BBS when you perform a manual dial, so use "UNKNOWN" (all caps) for
  1203. the name.  The same holds true if you suddenly detect a call which probably
  1204. occurred when someone typed an AT dialing command directly to the modem.
  1205. HostBBSName is truncated if it exceeds 40 chars.
  1206.    PhoneNumber obviously contains the phone number.  If this is a null string,
  1207. it means you have no idea what the phone number was.  This could be due to a
  1208. user typing an AT dialing command directly to the modem, or a call that is
  1209. already in progress when the program first starts up.  PhoneNumber is trun-
  1210. cated if it exceeds 32 chars.
  1211.    NOTE ABOUT PHONE NUMBERS: Vanity numbers such as "1-800-DEC-DEMO" are not
  1212. allowed in CDS.  You *must* convert them to their equivalent numeric format
  1213. before calling this procedure.  CDS phone bill analyzers view letters in the
  1214. phone number as redefinable prefix/suffix codes.  Consult the CDS proposal
  1215. document for further information.
  1216.    HostCallback is TRUE only when the comm program is in a host mode and has
  1217. been activated to return a call, rather than to place a call.  In this case,
  1218. the comm program should use 'Security Callback Feature' or something similar
  1219. as the CallerName, and use the logon attempter's name as the HostBBSName.
  1220.    Comment is any text you wish to add to the CDS record.  It is truncated if
  1221. it exceeds the maximum allowable length.}
  1222.  
  1223. BEGIN {LogOutgoingCall}
  1224. {Initialize.}
  1225. CDSIORESULT := 0;
  1226. OpenCDSFiles;
  1227.  
  1228. {Set up the call in progress.}
  1229. ActiveCall := TRUE;
  1230. WITH CallStarted
  1231.  DO BEGIN
  1232.     D := Today;
  1233.     T := CurrentTime
  1234.     END;
  1235. OutgoingCall := TRUE;
  1236. Port         := CommPort;
  1237. Speed        := CommSpeed;
  1238. DataBits     := CommBits;
  1239. Parity       := CommParity;
  1240. StopBits     := CommStopBits;
  1241.  
  1242. IF HostCallback
  1243.  THEN LogCDSRecord(HostCallbackID)
  1244.  ELSE LogCDSRecord(OutgoingCallID);
  1245. WriteOutgoingCallDetails({VAR} CDS,
  1246.                                CallerName,
  1247.                                Reason4Call,
  1248.                                HostBBSName,
  1249.                                PhoneNumber,
  1250.                                FALSE);
  1251. WriteOneLineComment({VAR} CDS,Comment);
  1252. WriteOutgoingCallDetails({VAR} SCF,
  1253.                                CallerName,
  1254.                                Reason4Call,
  1255.                                HostBBSName,
  1256.                                PhoneNumber,
  1257.                                FALSE);
  1258. WriteOneLineComment({VAR} SCF,Comment);
  1259.  
  1260. {Wrapup.}
  1261. CloseCDSFiles;
  1262. CDSIORESULT := IORESULT
  1263. END; {LogOutgoingCall}
  1264. {============================================================================}
  1265.  
  1266. {============================================================================}
  1267. PROCEDURE LogTerminatedCall(PasswordFailure : BOOLEAN;
  1268.                             CallContinuedOn : BOOLEAN;
  1269.                             CallEndedAbrupt : BOOLEAN;
  1270.                             AverageCPS      : WORD;
  1271.                             Comment         : STRING);
  1272.  
  1273.     {This procedure logs the termination of a call.  It assumes the ending
  1274. date/time is RIGHT NOW.  You should log a termination as soon as it is
  1275. detected.
  1276.  
  1277.    PasswordFailure indicates a host caller was terminated because of multiple
  1278. failed attempts to provide the proper password.
  1279.    CallContinuedOn indicates the call has NOT actually ended.  It means the
  1280. program is terminating when a call will still be going on.
  1281.    CallEndedAbrupt indicates a call ended abruptly.  This is true in cases
  1282. where the carrier is lost during a file transfer, for example.  Navigation
  1283. software (such as TAPCIS) may recognize a call terminated abnormally, and can
  1284. set this to TRUE.
  1285.    AverageCPS is the average chars per second over the entire call.  It is up
  1286. to the comm program to decide what value this contains.  A value of zero means
  1287. there will be no record of the average CPS in the CDS files.
  1288.    Comment is any text you wish to add to the CDS record.  It is truncated if
  1289. it exceeds the maximum allowable length.}
  1290.  
  1291. BEGIN {LogTerminatedCall}
  1292. {Initialize.}
  1293. CDSIORESULT := 0;
  1294. OpenCDSFiles;
  1295.  
  1296. {Wrap up the call in progress.}
  1297. ActiveCall  := FALSE;
  1298. WITH CallEnded
  1299.  DO BEGIN
  1300.     D := Today;
  1301.     T := CurrentTime
  1302.     END;
  1303.  
  1304. LogCDSRecord(EndedCallID);
  1305. WriteTerminatedCallDetails({VAR} CDS,
  1306.                                  PasswordFailure,
  1307.                                  CallContinuedOn,
  1308.                                  CallEndedAbrupt,
  1309.                                  AverageCPS);
  1310. WriteOneLineComment({VAR} CDS,Comment);
  1311. WriteTerminatedCallDetails({VAR} SCF,
  1312.                                  PasswordFailure,
  1313.                                  CallContinuedOn,
  1314.                                  CallEndedAbrupt,
  1315.                                  AverageCPS);
  1316. WriteOneLineComment({VAR} SCF,Comment);
  1317.  
  1318. {Wrapup.}
  1319. CloseCDSFiles;
  1320. CDSIORESULT := IORESULT
  1321. END; {LogTerminatedCall}
  1322. {============================================================================}
  1323.  
  1324. {============================================================================}
  1325. PROCEDURE WrapupCommCDS;
  1326.  
  1327.    {This procedure takes care of any loose strings when the comm program is
  1328. ready to terminate.  It MUST be called as the last routine in this unit.}
  1329.  
  1330. BEGIN {WrapupCommCDS}
  1331. CDSIORESULT := 0;
  1332.  
  1333. IF ActiveCall
  1334.  THEN LogTerminatedCall(FALSE,TRUE,FALSE,0,NullString);
  1335.  
  1336. CDSIORESULT := IORESULT
  1337. END; {WrapupCommCDS}
  1338. {============================================================================}
  1339.  
  1340.  
  1341. END. {CommCDS}
  1342.  
  1343.