/*****************************************************************
 * KingFisher Release 2
 * Application Programming Interface
 * Copyright © 1994,1995 Udo Schuermann
 * All rights reserved
 *****************************************************************
 * $VER: KingFisher_API 2.26 (11.4.97)
 *****************************************************************
 * This software belongs to Udo Schuermann (author) and may not be
 * redistributed or reproduced in any form without express written
 * permission from the author:
 *    Udo Schuermann
 *    7022 Hanover Parkway, Apt. C2
 *    Greenbelt, MD 20770-2049
 *
 *    walrus@wam.umd.edu
 *****************************************************************
 * By including this file and using the supplied functions, you
 * ensure greater compatibility in future versions and reduce the
 * chance of error through omitted parameters.  PLEASE USE THIS
 * API FOR YOUR APPLICATIONS AS MUCH AS POSSIBLE, RATHER THAN THE
 * THE MESSAGE PORT INTERFACE DIRECTLY!
 *
 * INSTRUCTIONS: In your project, include "kf-api.h" (which also
 * includes "kf.h" for you) to define what is needed to interface
 * with the KingFisher Release 2 Server.  Compile the file
 * "kf-api.c" into an object file (kf-api.o) and link it with your
 * other objects.
 *****************************************************************
 */

#ifndef KF_API_H
#define KF_API_H

#include "kf.h"


typedef struct KFMsg *KFHANDLE;   /* usage:  KFHANDLE myHandle  */

extern char KFAPIServerName[128];
extern BOOL KFAPIServerDebug;
extern BOOL KFAPISilentRun;

/* Some convenient and meaningful constructs, all beginning with KF_ */
#define  KF_CURRENT_FISH   0L              /* Use for KFGetFish() */
#define  KF_NIL_FISH       0L              /* "Not a valid fish" ID */
#define  KF_DISK(Handle)   Handle->DParam  /* Disk Number */
#define  KF_FISH(Handle)   Handle->BParam  /* Fish Number */
#define  KF_FLAGS(Handle)  Handle->FParam  /* Flags */
#define  KF_ERR(Handle)    Handle->Error   /* Error */


/*****************************************************************
 * The client may read and write the following variables.
 * The API functions write to these appropriate times.
 *****************************************************************
 */

/* When 'ExitRequested' becomes TRUE, the server has requested
 * us to quit as swiftly as possible so it can shutdown.  It is
 * important to comply without much delay!
 */
extern BOOL ExitRequested;

/* The client may receive asynchronous messages from the server,
 * that carry additional information about problems.  The last
 * such error code (AsyncErr) and text (AsyncMsg) are kept here.
 *    Your application should consult AsyncErr after unsuccessful
 * calls to one of these functions to possibly obtain additional
 * information and text on the problem that occurred.
 */
extern int   CallServerErr;
extern int   AsyncErr;
extern char  AsyncMsg[];



/*****************************************************************
 * function prototypes for the KingFisher API
 *****************************************************************
 */

/*****************************************************************
 * KFLogin()
 * Required as the first call to the server.  Issue this command with a
 * textual identifier, such as the name of your application.  A NULL
 * pointer is permitted, but strongly discouraged!
 *    The function returns a pointer to a KingFisher Server Message to
 * be used in ALL FUTURE TRANSACTIONS with the server.
 * NOTE: it is permitted for a single task to issue KFLogin() more than
 * once to enable transactions between multiple databases or to allow a
 * user to issue interactive commands while the main event loop keeps
 * issuing "background" requests to the server (such as a search.)
 *    You need to issue a KFLogout() command for every message returned
 * by the KFLogin() command.  The function returns NULL if it is not
 * possible to login to the server for one reason or another.
 */
struct KFMsg *KFLogin( char *Identifier );


/*****************************************************************
 * KFLogout()
 * Required as the last call to the server.  Issue this command when
 * you are finished with the server and wish to disconnect and exit.
 */
BOOL KFLogout( struct KFMsg *Msg );


/*****************************************************************
 * KFStatus()
 * Retrieves status information from the server.  The text returned in
 * the message .Buffer field is free-form and should not be relied upon
 * to be in any particular format.  It is meant to be presented to the
 * user.
 */
BOOL KFStatus( struct KFMsg *Msg );


/*****************************************************************
 * KFMaxClients()
 * Returns the server's maximum client count.  The following
 * ranges represent one of three types of the KFServer software:
 *   0..1       Not available; never released; bogus
 *   2          Freely Distributable KFServer
 *   3..32767   Beta test versions, not for public use
 *   32768+     Registered version
 */
ULONG KFMaxClients( struct KFMsg *Msg );


/*****************************************************************
 * KFCurFish()
 * Retrieves the current position in the database, i.e. the current
 * record.  The value returned may not fall in the proper range of
 * available records if improper positions have been selected before.
 */
ULONG KFCurFish( struct KFMsg *Msg );


/*****************************************************************
 * KFCurFlags()
 * Retrieves the flags of the current fish (record) in the database.
 * If the current position in the database is not a valid record,
 * then the information returned by this call will be undefined.
 */
UWORD KFCurFlags( struct KFMsg *Msg );


/*****************************************************************
 * KFCurDisk()
 * Retrieves the disk position of the current fish (record).
 * If the current position in the database is not a valid record,
 * then the disk number returned by this call will be undefined.
 */
ULONG KFCurDisk( struct KFMsg *Msg );


/*****************************************************************
 * KFCurDatabaseDescription()
 * Returns the long, descriptive name of the currently selected
 * database.  This allows a program to present the user with a
 * nice, understandable title for the current database in use.
 */
char *KFCurDatabaseDescription( struct KFMsg *Msg );


/*****************************************************************
 * KFCurDatabaseName()
 * Returnes the name of the currently selected database.  This
 * allows a program to make an alternate choice and "return" to
 * the current database at will (see KFSelectDatabase() for more
 * important information.)
 */
char *KFCurDatabaseName( struct KFMsg *Msg );


/*****************************************************************
 * KFCurDatabaseSize()
 * Returns the number of records stored in the database.  If the
 * function returns 0, then the database is empty (contains no
 * records.)
 */
ULONG KFCurDatabaseSize( struct KFMsg *Msg );


/*****************************************************************
 * KFQuickIndex()
 * Returns a pointer to the quick index.  In addition, the message
 * field .DParam, when interpreted as a string, points to the name
 * of the field that the index pertains to.
 *
 * The QuickIndex is a \0 terminated string:  "Name\nName2\n"
 */
char *KFQuickIndex( struct KFMsg *Msg );



/*****************************************************************
 * KFSelectFish()
 * Change the current position in the database.
 */
BOOL KFSelectFish( struct KFMsg *Msg, ULONG FishNumber );


/*****************************************************************
 * KFNextVersion()
 * KFPrevVersion()
 * Obtain record numbers of the next or previous version; if these
 * numbers are == 0L then no such fish exists; otherwise a call
 * can be made to load the selected fish.
 * These calls are informational only, and do NOT cause the server
 * to select a new fish; i.e. the currently defined record remains
 * unchanged by these calls.
 */
ULONG KFNextVersion( struct KFMsg *Msg );
ULONG KFPrevVersion( struct KFMsg *Msg );

/*****************************************************************
 * KFSetNextVersion()
 * KFSetPrevVersion()
 * Update the next or previous version links for the current fish;
 * a link value of 0L will clear the link.  The function returns
 * -1L in case of a failure OR the previous value of that link.
 */
ULONG KFSetNextVersion( struct KFMsg *Msg, ULONG LinkValue );
ULONG KFSetPrevVersion( struct KFMsg *Msg, ULONG LinkValue );

/*****************************************************************
 * KFListDatabases()
 * Retrieves a list of database names (those files with ".kfdb" at
 * the end of their names) into the message .Buffer;  The names
 * will be separated from each other by a newline \n and the list
 * is terminated by a NUL (\0)
 *    The format of the buffer will always be:
 *       Descriptive text #1\01
 *       filename1.kfdb\n
 *       Descriptive text #2\01
 *       filename2.kfdb\n
 *       \0
 * Note the continued use of \n as line terminator but the
 * pre-pended descriptive text which is separated from the
 * filename with a \1 (ASCII 01, ^A); the KFSelectDatabase()
 * function expects to be given the string AFTER the \01
 * character!
 */
BOOL KFListDatabases( struct KFMsg *Msg );


/*****************************************************************
 * KFSelectDatabase()
 * Selects a new database by name.  The .kfdb extension is not
 * strictly required, but the server will first try to open the
 * database by the name exactly as given, and will THEN try it
 * again (if failed) with the .kfdb extension added.
 *    The name of the file may be terminated by either the
 * standard ASCII NUL (\0) or a newline (\n) -- the latter is
 * a convenience feature for use of this function in conjunction
 * with KFListDatabases() from whose .Buffer it may be desireable
 * to simply point at one of the names without regard if they are
 * terminated with the \0 or \n.
 *    The current position in the new database will be set to the
 * first record.  If the function fails (returns FALSE) then the
 * previously active database remains available undisturbed.
 *    The R/W status of the database index is described by the
 * Msg->BParam that is returned in case of a successful call.  If
 * this value is 0 the index is not writable, otherwise it is.
 */
BOOL KFSelectDatabase( struct KFMsg *Msg, char *Filename );


/*****************************************************************
 * KFSetFlag()
 * KFClrFlag()
 * KFFindFlag()
 * Sets or clears a particular flag for the current fish.  The
 * flag's mask value is given in the second parameter.
 * KFFindFlag() locates the next/previous fish matching the masks.
 */
BOOL KFSetFlag( struct KFMsg *Msg, UWORD Mask );
BOOL KFClrFlag( struct KFMsg *Msg, UWORD Mask );
BOOL KFFindFlag( struct KFMsg *Msg, BOOL Forward, UWORD MatchMask, UWORD AvoidMask );


/*****************************************************************
 * KFFindNextUsedLink()
 * Returns the record number of the record that has either or both
 * the previous/next VersionLinks set.  The operation begins with
 * the indicated record (and may return that same record number!)
 * The function returns the record number of the next matching
 * record, this being a value 1+ if successful, 0 if not.
 */
ULONG KFFindNextUsedLink( struct KFMsg *Msg, ULONG FishNum );


/*****************************************************************
 * KFGetFish()
 * Retrieve the current (or a specific) record from the current
 * database.  If the 'FishNumber' parameter is set to 0 (as
 * opposed to a valid record number 1 or greater) then the
 * current record will be retrieved.  If a value greater than
 * 0 is provided, then that specific record is retrieved.
 * On successful return, .BParam has the fish number, .DParam
 * has the disk number, and .FParam contains the returned fish's
 * flags.
 * NOTE: this function will fail if the indicated database is
 * in use by any client application that has made calls to the
 * KFAddFish() function without having released the database
 * with a call to KFEndAdding().
 */
BOOL KFGetFish( struct KFMsg *Msg, ULONG FishNumber );


/*****************************************************************
 * KFGetDisk()
 * Retrieve the first fish from the database that is stored on
 * the indicated disk (according to the index.)  The function
 * returns FALSE if such a disk cannot be located.  All disks
 * must be numbered 1 or greater.  Values of 0 or less are not
 * valid and will be rejected.
 *    The current fish is retrieved in the same way as if that
 * fish's exact record number had been given to KFGetFish();
 * On successful return, all parameters are set as in the
 * KFGetDisk() call.
 * NOTE: this function will fail if the indicated database is
 * in use by any client application that has made calls to the
 * KFAddFish() function without having released the database
 * with a call to KFEndAdding().
 */
BOOL KFGetDisk( struct KFMsg *Msg, ULONG DiskNumber );


/* KFNextFish()
 * Selects the fish following the current position.
 */
BOOL KFNextFish( struct KFMsg *Msg );


/* KFPrevFish()
 * Selects the fish preceeding the current position.
 */
BOOL KFPrevFish( struct KFMsg *Msg );


/*****************************************************************
 * KFAddFish()
 * Adds the description in the .Buffer to the END of the current
 * database and marks the Disk, Flags, and Prev- and Next-Version
 * values into the index.
 * NOTE: this function may fail for numerous reasons.  One thing
 * to watch out for, especially, is that the function may fail if
 * anyone else ALSO has access to the database.  If your client
 * is the only one using a particular database, then the database
 * is blocked until released with KFEndAdding().
 */
BOOL KFAddFish( struct KFMsg *Msg, UWORD Disk, UWORD Flags, LONG PrevVersion, LONG NextVersion );


/*****************************************************************
 * KFEndAdding()
 * You *MUST* call this function after having added record(s) to
 * the database.  You should not call this function after EACH
 * addition, but only when everything you want to add has been
 * added.
 */
BOOL KFEndAdding( struct KFMsg *Msg );


/*****************************************************************
 * KFTruncate()
 * Truncates the database at the current position and moves back
 * one fish; the return value is the new position in the database.
 * A return value of -1 indicates an error, 0 means the database
 * no longer contains any records, and 1+ is a valid position.
 */
LONG KFTruncate( struct KFMsg *Msg );


/*****************************************************************
 * KFParseFile()
 * When this function is called the first time, it opens the
 * indicated file, locates, and returns the first database
 * record from it.
 *    When called again, AFTER THE PREVIOUS CALL RETURNED
 * TRUE, this function will continue to scan the indicated
 * file, returning database records one at a time.  As long
 * as the function returns TRUE, you may continue to call
 * it, and the filename parameter serves no further purpose.
 *    Once this function returns FALSE (on its first call or
 * any subsequent call) the parsing is terminated and you
 * should not use KFEndParsing() (see below)
 *    If you wish to interrupt parsing a file BEFORE the
 * function returns FALSE, the you MUST use KFEndParsing()
 * to tell the server that you have no further interest in
 * the file that it is prepared to continue parsing.
 */
BOOL KFParseFile( struct KFMsg *Msg, char *Filename );


/*****************************************************************
 * KFEndParsing()
 * This function needs to be called whenever you have called
 * upon the services of KFParseFile() but you wish to stop
 * retrieving records from that file BEFORE the KFParseFile()
 * function returns FALSE (i.e. no more records or another
 * problem of sorts.)
BOOL KFEndParsing( struct KFMsg *Msg );


/*****************************************************************
 * KFReindex()
 * Rebuilds the index for the current database.  If more than
 * one client has access to the current database, this call
 * will fail.  After this function completes successfully,
 * the current database record is reset to 1.
 */
BOOL KFReindex( struct KFMsg *Msg );


/*****************************************************************
 * KFLockDB()
 * KFUnlockDB()
 * Lock and unlock the database for operations that do not already
 * provide their own locking.  This is an operation especially
 * useful when modifying version links or performing other actions
 * that should not occur while another client has access to the
 * database.
 *    The functions return TRUE if they succeed
 */
BOOL KFLockDB( struct KFMsg *Msg );
BOOL KFUnlockDB( struct KFMsg *Msg );


/* End of File */
#endif   /* ifndef kf_api_h */


