/* DiavoloHandle.c -- handle out some Diavolo  functions */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <clib/exec_protos.h>

#include <clib/locale_protos.h>             /* Contains all prototypes for Amiga functions. May
                                               have a different name when using another compiler */
#include <exec/exec.h>

#include "DiavoloPrefs.h"       /* Contains documented preference structure and constants */
#include "DiavoloAPI.h"         /* Structures, constants and documentation of Diavolo API */

#include "DiavoloHandle.h"                  /* the respective header 8-D */


#define RELEASE_4   4                       /* Self-read Diavolo Version */
#define RELEASE_3   3
#define RELEASE_ERR -1

#define DI_SIZE_3   1040                    /* DiavoloInquiry structure sizes with respect */
#define DI_SIZE_4   1068                    /* to Diavolo version (3.4 or 2000) */

#define DOC_RC_OK   0                       /* return codes for DoCommand(): ok*/
#define DOC_RC_ERR  1                       /* errors in Diavolo dialog */
#define DOC_RC_TER  2                       /* CTRL-C terminate */

/* local variales */

struct MsgPort * MyReplyPort;               /* Global Reply Port. Will be used by Diavolo to send its
                                               messages to the client */

struct MsgPort * APIPort;                   /* API Port of Diavolo Backup. Global message port which
                                                must be used to send messages to Diavolo */

struct DiavoloInquiry * DInquiry;           /* shared message structures */
struct DiavoloAPIMsg G_APIMsg;

BOOL  Quit;                                 /* TRUE: Quit requested by Diavolo */

int d_release;                              /* diavolo release code used as a workaround for changes */
                                            /* in new diavolo 2000 structures (we hope correct) */


/* local protos */

void CheckDAPIMsg(struct DiavoloAPIMsg   *APIMsg);

#ifdef VERBOSE
void print_IStat(void);
#endif
int per_cent(ULONG den, ULONG num);


/* functions */

void    CheckRequest(struct    DiavoloAPIMsg   *APIMsg)

/* Will be used to process incoming request messages. After a client has made contact with
   Diavolo, before a requester is displayed to the user, a message will be sent to the client.
   The client can answer this request itself, so the user never sees the request, or make Diavolo
   display the request as normal. Anyway, the client MUST reply the request as fast as possible,
   so the message port must be always watched for incoming messages. If the client does not reply
   a message, there could be a deadlock (Diavolo waiting for client and client waiting for
   Diavolo).

   Modify this routine to customize the clients reaction to requesters. Look at the DAPI_RC_...
   defines at the end of DiavoloAPI.h for all possible request codes and their meaning.

*/

{
    ULONG                       RetVal;


    /* At first the client displays the requester text. This is just for testing and
       should not be used in a final client application - at least not THIS way. */

    printf("Title: %s\n",APIMsg->DAPI_Ptr1);
    printf("Body:\n%s\n",APIMsg->DAPI_Ptr2);
    printf("Gadgets: %s\n",APIMsg->DAPI_Ptr3);
    printf("Code: %ld\n",APIMsg->DAPI_Arg1);


    /* This switch/case statement decides what to do with the requester. */

    switch(APIMsg->DAPI_Arg1)
    {
        /* The following requests shall not be displayed to the user. Instead Diavolo should
           react as if the user presses RETRY. */

        case DAPI_RC_INSERTDISK:        /* Insert disk in any drive... */
        case DAPI_RC_INSERTDIRDISK:     /* Insert first disk in any drive. */
        case DAPI_RC_BACKDISK:          /* This disk contains another backup... */
        case DAPI_RC_DOSDISK:           /* This disk is DOS formatted ... */
        case DAPI_RC_ALIENTAPE:         /* This tape contains unreadable data or is empty ... */

            RetVal = 1;                 /* RetVal will be used as a replycode to Diavolo.
                                           1 means the leftmost option, RETRY in these cases. */
            break;

        default:                        /* In all other cases... */

            RetVal = ~0;                /* A RetVal of ~0 (bitwise NOT 0, in other words all bits set)
                                           means that Diavolo should display the requester as normal */
    }

    APIMsg->DAPI_Arg1 = RetVal;         /* Return the message with RetVal set in Arg1 */
    ReplyMsg((struct Message *)APIMsg);
}




void    CheckDAPIMsg(struct DiavoloAPIMsg   *APIMsg)

/* Check incoming messages. */

{
    if(APIMsg->DAPI_Message.mn_Node.ln_Type == NT_REPLYMSG)
    /* The received message was a reply. Normally replies will only be received after you've sended
       a message to Diavolo in the first place. This example is written in a way that every
       routine knows its sent messages and handles its replies itself, so this generic routine
       should never has to handle replies. */
    {
        printf("Reply received. Don't know original message. ERROR!\n");
    }

    else
    {
        /* What kind of message is this? */

        switch(APIMsg->DAPI_Command)
        {
            case    DAPI_REQUEST:
                /* Diavolo has a request. CheckRequest (see above) handles them */
                CheckRequest(APIMsg);
                break;

            case    DAPI_CLOSEDOWN:
                /* Diavolo is closing down. The client is informed that it has to cut down
                   the link to Diavolo, so it can complete the closedown. */

                Quit = TRUE;            /* Set global Quit flag to TRUE */
                ReplyMsg((struct Message *)APIMsg);       /* Return message */
                break;

            default:
                /* Another - unknown - message has arrived. Diavolo only sends the two
                   messages handled above or replies. */

                printf("Unknown message. Command: %lx\n",APIMsg->DAPI_Command);
                ReplyMsg((struct Message *)APIMsg);
                break;
        }
    }
}



int DoCommand(struct DiavoloAPIMsg *APIMsg, struct MsgPort * APIPort)

/* Send a command to Diavolo and wait for its completion (its reply).

   This routine handles all incoming message (also requests) and waits until the command
   was replied.

   Use this for all commands you want to send synchronously (which should be most). You
   cannot use them for asynchronous command, which are used to initiate an operation.
   These are DAPI_STARTBACKUP, DAPI_STARTSCAN and DAPI_STARTRESTORE. Use seperate
   routines for these commands (see below).

   The parameter APIMsg must be filled with the correct parameters you want to send to
   Diavolo (also the command code itself). After the routine replies you can find the
   result codes set by Diavolo in the same structure.

*/

{
    struct  DiavoloAPIMsg       *Reply;
    int Ok;
    ULONG RetC;
    ULONG tempsigs, replysigmask;

    /* Set Replyport of the message to send to the global client message port */
    APIMsg->DAPI_Message.mn_ReplyPort = MyReplyPort;

    /* Send the message to Diavolo's API Port */
    PutMsg(APIPort, (struct Message *)APIMsg);

    do
    {
        /* This is a generic method of waiting for a message. If you want to check more
           than one message port, you'll have to add more bits to the Wait() mask. */

        replysigmask = 1l << MyReplyPort->mp_SigBit;

        while(! (Reply = (struct DiavoloAPIMsg *)GetMsg(MyReplyPort)))
        {
            tempsigs = Wait(replysigmask | SIGBREAKF_CTRL_C);

            if (tempsigs == SIGBREAKF_CTRL_C)
            {
#ifdef VERBOSE
                printf("DiavoloHandle: DoCommand() got CTRL-C\n");
#endif
                return(DOC_RC_TER);

            }
        }

        if(Reply->DAPI_Message.mn_Node.ln_Type != NT_REPLYMSG || Reply != APIMsg)
        {
            /* The received message wasn't the reply for our own message, so process it */
            printf("DiavoloHandle: The received message wasn't the reply for our own message\n");

            CheckDAPIMsg(Reply);
            Reply = NULL;           /* No, we're not finished yet */
        }
        else
        {
            /* release workaround needed here !!! 8-( */
            if (d_release == 4)
                RetC = Reply->pad[3];
            else /* (d_release == 3) */
                RetC = Reply->DAPI_Errorcode;


            /* Our message has been replied. Fine, now look if there was an error
               set in the reply: */

            switch(RetC)
            {
                case DAPI_EC_NOERROR:
                    /* Everything was fine! */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: No error!\n");
#endif
                    Ok = DOC_RC_OK;
                    break;

                case DAPI_EC_INUSE:
                    /* Diavolo's messageport is in use by another application */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: In Use error\n");
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_NOTAVAILABLE:
                    /* The sent command is not available at this moment or entirely unknown */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Command not available!\n");
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_NOTMETYET:
                    /* You have not intiated the dialogue using DAPI_RENDEZVOUS yet */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Programs not met yet!\n");
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_INVALIDCONFIG:
                    /* The new configuration was invalid */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Invalid config!\n");
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_SELECTFAILED:
                    /* The selection (in DAPI_BACKSELECT and DAPI_RESTSELECT) failed */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Selection failed. Code: %ld!\n", Reply->DAPI_Arg1);
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_OPPENDING:
                    /* You cannot cut the connection (using DAPI_GOODBYE) while a client
                       intiated operation is in progress. Cancel the operation first! */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Operation pending, Goodbye not possible!\n");
#endif
                    Ok = DOC_RC_ERR;
                    break;

                case DAPI_EC_OPFAILED:
                    /* The oepration failed */
#ifdef DEBUG
                    printf("DiavoloHandle: Reply: Operation failed, Code: %ld!\n",Reply->DAPI_Arg1);
#endif
                    Ok = DOC_RC_ERR;
                    break;

                default:
#ifdef DEBUG
                    printf("DiavoloHandle: Unknown errorcode: %ld\n", RetC);
#endif
                    Ok = DOC_RC_ERR;
            }
        }
    }
    while(Reply == NULL);
    return(Ok);
}


BOOL setup_diavolo(void)
{
    char RendezvousName[30];

    /* allocate memory for inquiry structure */
    if( (DInquiry = (struct DiavoloInquiry*) malloc(sizeof(struct DiavoloInquiry))) == NULL )
    {
#ifdef DEBUG
        printf("DiavoloHandle.c: Error allocating memory for inquiry structure!\n");
#endif
        return (FALSE);
    }

    /* First create our own message port */
    if(! (MyReplyPort = CreateMsgPort()))
    {
#ifdef DEBUG
        printf("DiavoloHandle.c: Error creating own message port!\n");
#endif
        return (FALSE);         /* Failed */
    }

    sprintf(RendezvousName,RENDEZVOUS_NAME,1);

    /* Use forbid to secure the FindPort Operation (suggested in Exec autodocs) */
    Forbid();

    /* Look for Diavolo message port. This will only look for Diavolo.1 */
    if(! (APIPort = FindPort(RendezvousName)))
    {
        Permit();
#ifdef DEBUG
        printf("DiavoloHandle.c: Couldn't find Diavolo API port!\n");
#endif
        DeleteMsgPort(MyReplyPort);
        return (FALSE);
    }

    Permit();

    return(TRUE);
}


/*
 * cleanup diavolo communication
 */

void cleanup_diavolo(void)
{
    DeleteMsgPort(MyReplyPort);
    free(DInquiry);
}


#ifdef DEBUG
void print_TStat(UBYTE TS)
{
/* Values for DAPI_TapeStatus*/
    switch (TS) {
        case TAPSTAT_REWIND     :   printf("Tape is rewinding\n");
                                    break;
        case TAPSTAT_SEEK       :   printf("Tape is seeking position\n");
                                    break;
        case TAPSTAT_WRITEINDEX :   printf("Writing index on tape\n");
                                    break;
        case TAPSTAT_READINDEX  :   printf("Reading index from tape\n");
                                    break;
        case TAPSTAT_STANDBY    :   printf("Tape standing by\n");
                                    break;
        case TAPSTAT_WRITING    :   printf("Writing data to tape\n");
                                    break;
        case TAPSTAT_READING    :   printf("Reading data from tape\n");
                                    break;
        case TAPSTAT_PARTITION  :   printf("Partitioning tape\n");
                                    break;
        default                 :   printf("Tape Status Error\n");
                                    break;
    }
}
#endif

#ifdef VERBOSE
void print_IStat(void)
{
    int fp, dp, bp, wp, pp, gp;
    struct DiavoloInquiry4 * D4Inq;

    printf("Diavolo Release: %d\n", d_release);

    if (d_release == RELEASE_3)
    {
    printf("Backup name: %s\n", DInquiry->DAPI_BackName);          /* Name of backup */
    printf("ID of backup: %ld\n", DInquiry->DAPI_ID);                  /* ID of backup */
    printf("Size of backup: %ld\n", DInquiry->DAPI_BackSize);          /* Size of backup */
    printf("Files in backup: %ld\n", DInquiry->DAPI_BackFiles);        /* Files in backup */
    printf("Dirs in backup: %ld\n", DInquiry->DAPI_BackDirs);          /* Dirs in backup */
    printf("Number of partitions: %ld\n", DInquiry->DAPI_BackVolumes); /* Number of partitions in backup */

    printf("Cur file: %s\n", DInquiry->DAPI_File);                 /* Current Filename being processed */
    printf("Cur dir: %s\n", DInquiry->DAPI_Dir);                  /* Current Directory being processed */

        fp = per_cent( DInquiry->DAPI_BackFiles, DInquiry->DAPI_FileCount);

        dp = per_cent( DInquiry->DAPI_BackDirs, DInquiry->DAPI_DirCount);

        bp = per_cent( DInquiry->DAPI_BackSize, DInquiry->DAPI_ByteCount);

        wp = per_cent( DInquiry->DAPI_BackSize, DInquiry->DAPI_Written);

        pp = per_cent( DInquiry->DAPI_BackSize, DInquiry->DAPI_Unpacked);

        gp = per_cent( DInquiry->DAPI_Unpacked, DInquiry->DAPI_Packed);

    printf("File count: %ld (%d%%)\n", DInquiry->DAPI_FileCount, fp);             /* Number of files processed (incl. acutal file) */
    printf("Dir count: %ld (%d%%)\n", DInquiry->DAPI_DirCount, dp);               /* Number of dirs processed (incl. actual dir) */
    printf("Byte count: %ld (%d%%)\n", DInquiry->DAPI_ByteCount, bp);             /* Number of bytes processed */
    printf("Bytes Written/Read: %ld (%d%%)\n", DInquiry->DAPI_Written, wp);            /* Number of bytes written/read to/from medium */
    printf("Processed Bytes (unpacked): %ld (%d%%)\n", DInquiry->DAPI_Unpacked, pp);
    printf("Processed Bytes (packed); %ld (%d%% of orig)\n", DInquiry->DAPI_Packed, gp);
    }
    else if (d_release == RELEASE_4)
    {
        D4Inq = (struct DiavoloInquiry4 *) DInquiry;

    printf("Backup name: %s\n",  D4Inq->DAPI_BackName);          /* Name of backup */
    printf("ID of backup: %ld\n",  D4Inq->DAPI_ID);                  /* ID of backup */
    printf("Size of backup: Kbytes %ld",  D4Inq->DAPI_BackSize.kbytes);          /* Size of backup */
    printf(" bytes %ld\n",  D4Inq->DAPI_BackSize.bytes);          /* Size of backup */
    printf("Files in backup: %ld\n",  D4Inq->DAPI_BackFiles);        /* Files in backup */
    printf("Dirs in backup: %ld\n",  D4Inq->DAPI_BackDirs);          /* Dirs in backup */
    printf("Number of partitions: %ld\n",  D4Inq->DAPI_BackVolumes); /* Number of partitions in backup */

    printf("Cur file: %s\n",  D4Inq->DAPI_File);                 /* Current Filename being processed */
    printf("Cur dir: %s\n",  D4Inq->DAPI_Dir);                  /* Current Directory being processed */

        fp = per_cent( D4Inq->DAPI_BackFiles, D4Inq->DAPI_FileCount);

        dp = per_cent( D4Inq->DAPI_BackDirs, D4Inq->DAPI_DirCount);

        bp = per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_ByteCount.kbytes);

        wp = per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_Written.kbytes);

        pp = per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_Unpacked.kbytes);

        gp = per_cent( D4Inq->DAPI_Unpacked.kbytes, D4Inq->DAPI_Packed.kbytes);

    printf("File count: %ld (%d%%)\n",  D4Inq->DAPI_FileCount, fp);             /* Number of files processed (incl. acutal file) */
    printf("Dir count: %ld (%d%%)\n",  D4Inq->DAPI_DirCount, dp);               /* Number of dirs processed (incl. actual dir) */
    printf("Byte count: Kbytes %ld",  D4Inq->DAPI_ByteCount.kbytes);             /* Number of bytes processed */
    printf(" bytes %ld (%d%%)\n",  D4Inq->DAPI_ByteCount.bytes, bp);             /* Number of bytes processed */

    printf("Bytes Written/Read: Kbytes %ld",  D4Inq->DAPI_Written.kbytes);            /* Number of bytes written/read to/from medium */
    printf(" bytes %ld (%d%%)\n",  D4Inq->DAPI_Written.bytes, wp);            /* Number of bytes written/read to/from medium */
    printf("Processed Bytes: Kbytes %ld",  D4Inq->DAPI_Unpacked.kbytes);            /* Number of bytes written/read to/from medium */
    printf(" bytes %ld (%d%%)\n",  D4Inq->DAPI_Unpacked.bytes, pp);            /* Number of bytes written/read to/from medium */
    printf("Processed Bytes (packed): Kbytes %ld",  D4Inq->DAPI_Packed.kbytes);
    printf(" bytes %ld (%d%% of orig)\n",  D4Inq->DAPI_Packed.bytes, gp);
    }
    else printf("Release unknown\n");
}
#endif



/*
 * inquiry actual diavolo state
 */

BOOL inquiry_diavolo(char * OutMessage)
{
    static int DIsize, pc;
    int rc, tmp;
    struct DiavoloInquiry4 * D4Inq;
    float conv;
    char tmsg[6];
    UBYTE tapsta;

#ifdef DEBUG
    printf("DiavoloHandle.c: sending an inquiry request\n");
#endif
    G_APIMsg.DAPI_Command = DAPI_INQUIRY;
    G_APIMsg.DAPI_Arg1 = sizeof(struct DiavoloInquiry);
    G_APIMsg.DAPI_Ptr1 = DInquiry;

    rc = DoCommand(&G_APIMsg, APIPort);
    if (rc != DOC_RC_TER )
    {
        if ( DInquiry->DAPI_Magic != INQ_MAGIC)
        {
#ifdef DEBUG
            printf("DiavoloHandle.c: Magic Code of inquiry not correct!\n");
#endif
            return(FALSE);
        }

        /* this is how to get Diavolo release version */
        if (OutMessage == NULL)
        {
            DIsize = DInquiry->DAPI_Size;
            if (DIsize == DI_SIZE_4) d_release = RELEASE_4;
            else if (DIsize == DI_SIZE_3) d_release = RELEASE_3;
            else {
                d_release = RELEASE_ERR;
                return (FALSE);
            }
#ifdef SHOW_D_VERSION
            printf("Diavolo Backup Release Version detected: %d\n", d_release);
#endif
            return(TRUE);
        }

        if (DInquiry->DAPI_Size != DIsize)
        {
#ifdef DEBUG
            printf("DiavoloHandle.c: inquiry size mismatch - expected %d, got %d\n", DIsize,  DInquiry->DAPI_Size );
#endif
         //   return(FALSE);
        }

        D4Inq = (struct DiavoloInquiry4 *) DInquiry;

        switch (DInquiry->DAPI_ActualStatus) /* this is idependent from release */
        {
            case INQSTATUS_MENU          :
                sprintf(OutMessage, "IDLE");
#ifdef VERBOSE
                printf("Inquiry: Main menu \n");
#endif
                break;

            case INQSTATUS_DEVSELBACK    :
                sprintf(OutMessage, "SEL.b");
#ifdef VERBOSE
                printf("Inquiry: Device selection for backup\n");
#endif
                break;

            case INQSTATUS_DEVSELREST    :
                sprintf(OutMessage, "SEL.r");
#ifdef VERBOSE
                printf("Inquiry: Device selection for restore \n");
#endif
                break;

            case INQSTATUS_DEVSELCOMP    :
                sprintf(OutMessage, "SEL.c");
#ifdef VERBOSE
                printf("Inquiry: Device selection for compare \n");
#endif
                break;

            case INQSTATUS_BACKUP        :
                if (d_release == RELEASE_3)
                {
                        /* workaround due to DAPI_BackSize being always 0 in rel. 3*/
                        pc = per_cent(DInquiry->DAPI_BackFiles, DInquiry->DAPI_FileCount);
                }
                else if (d_release == RELEASE_4)
                {
                    if (D4Inq->DAPI_Unpacked.kbytes == 0) /* no compression */
                        pc = per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_Written.kbytes );
                    else {
                        /* compression ratio */
                        conv = ((float) (D4Inq->DAPI_Packed.kbytes)) / ((float) (D4Inq->DAPI_Unpacked.kbytes));

                        /* return a meaningful percent on compressed data */
                        tmp = per_cent( ((ULONG)( ((float)(D4Inq->DAPI_BackSize.kbytes))*conv)), D4Inq->DAPI_Written.kbytes );

                        /* insures monotonic variaton of percent */
                        if (tmp > pc) pc = tmp;
                    }
                }
                sprintf(tmsg, "b.%2u", pc);
                if (strlen(tmsg) <= 4) sprintf(OutMessage, " %s", tmsg);
                else sprintf(OutMessage, "%s", tmsg);
#ifdef VERBOSE
                printf("Inquiry: Backup operation\n");
                                            print_IStat();
#endif
                break;

            case INQSTATUS_BACKUPSTAT    :
                sprintf(OutMessage, "STA.b");
#ifdef VERBOSE
                printf("Inquiry: Statistics after backup complete \n");
#endif
                break;

            case INQSTATUS_SCANNING      :
                sprintf(OutMessage, "SCAN");
#ifdef VERBOSE
                printf("Inquiry: Scanning for backup index \n");
#endif
                break;

            case INQSTATUS_RESTORE       :
                if (d_release == RELEASE_3) sprintf(tmsg, "r.%2d", per_cent(DInquiry->DAPI_BackFiles, DInquiry->DAPI_FileCount) );
                else if (d_release == RELEASE_4) sprintf(tmsg, "r.%2d", per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_ByteCount.kbytes));
                if (strlen(tmsg) <= 4) sprintf(OutMessage, " %s", tmsg);
                else sprintf(OutMessage, "%s", tmsg);
#ifdef VERBOSE
                printf("Inquiry: Restore operation \n");
                print_IStat();
#endif
                break;

            case INQSTATUS_RESTORESTAT   :
                sprintf(OutMessage, "STA.r");
#ifdef VERBOSE
                printf("Inquiry: Statistics after restore complete \n");
#endif
                break;

            case INQSTATUS_COMPARE       :
                if (d_release == RELEASE_3) sprintf(tmsg, "c.%2d", per_cent(DInquiry->DAPI_BackFiles, DInquiry->DAPI_FileCount) );
                else if (d_release == RELEASE_4) sprintf(tmsg, " c.%2d", per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_ByteCount.kbytes));
                if (strlen(tmsg) <= 4) sprintf(OutMessage, " %s", tmsg);
                else sprintf(OutMessage, "%s", tmsg);
#ifdef VERBOSE
                printf("Inquiry: Compare operation \n");
                print_IStat();
#endif
                break;

            case INQSTATUS_COMPARESTAT   :
                sprintf(OutMessage, "STA.c");
#ifdef VERBOSE
                printf("Inquiry: Statistics after compare complete \n");
#endif
                break;

            case INQSTATUS_IMMEDCOMPARE  :
                if (d_release == RELEASE_3) sprintf(tmsg, "c.%2d", per_cent(DInquiry->DAPI_BackFiles, DInquiry->DAPI_FileCount) );
                else if (d_release == RELEASE_4) sprintf(tmsg, "c.%2d", per_cent( D4Inq->DAPI_BackSize.kbytes, D4Inq->DAPI_ByteCount.kbytes));
                if (strlen(tmsg) <= 4) sprintf(OutMessage, " %s", tmsg);
                else sprintf(OutMessage, "%s", tmsg);
#ifdef VERBOSE
                printf("Inquiry: Compare right after backup (without scan)\n");
                print_IStat();
#endif
                break;

            case INQSTATUS_UNKNOWN       :
                sprintf(OutMessage, "UNK");
#ifdef VERBOSE
                printf("Inquiry: Current INQSTATUS undefined\n");
#endif
                break;

            default                      :
                sprintf(OutMessage, "ERR");
#ifdef VERBOSE
                printf("Inquiry: ERROR: undefined situation\n");
#endif
                break;
        }   /* switch */

        if (d_release == RELEASE_3) tapsta = DInquiry->DAPI_TapeStatus;
        else if (d_release == RELEASE_4) tapsta = D4Inq->DAPI_TapeStatus;
#ifdef DEBUG
        print_TStat(tapsta);
#endif
        switch(tapsta) {
        case TAPSTAT_REWIND     :   sprintf(OutMessage, "BACK");
                                    break;
        case TAPSTAT_SEEK       :   sprintf(OutMessage, "SEEK");
                                    break;
        case TAPSTAT_WRITEINDEX :   sprintf(OutMessage, " IX ");
                                    break;
        case TAPSTAT_READINDEX  :   sprintf(OutMessage, " IX ");
                                    break;
        case TAPSTAT_STANDBY    :   sprintf(OutMessage, "TAPE");
                                    break;
        case TAPSTAT_PARTITION  :   sprintf(OutMessage, "PRTN");
                                    break;
        case TAPSTAT_WRITING    :   break;
        case TAPSTAT_READING    :   break;
        default                 :   break;
        }
    }
    else return(FALSE); /* CTRL-C break by DoCommand()*/

    return(TRUE);
}


int per_cent(ULONG den, ULONG num)
{
    int tr;

    if ( den != 0 )
    {
        tr = (int) (( ((float)num) *100) / ((float)den)) ;

        return(tr);
    }
    else return(0);
}
