package Zephyr;

use strict;
use Carp;
use vars qw($VERSION $error @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD);

require Exporter;
require DynaLoader;
require AutoLoader;

@ISA = qw(Exporter DynaLoader);

$VERSION = '0.102';

# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT_OK = qw(
		ZERR_AUTHFAIL ZERR_BADFIELD ZERR_BADPKT ZERR_EOF
		ZERR_FIELDLEN ZERR_HEADERLEN ZERR_HMDEAD ZERR_HMPORT
		ZERR_ILLVAL ZERR_INTERNAL ZERR_LOGINFAIL ZERR_NOLOCATIONS
		ZERR_NOMORELOCS ZERR_NOMORESUBSCRIPTIONS ZERR_NONE
		ZERR_NONOTICE ZERR_NOPORT ZERR_NOSUBSCRIPTIONS ZERR_PKTLEN
		ZERR_PORTINUSE ZERR_QLEN ZERR_SERVNAK ZERR_TOOMANYSUBS
		ZERR_VERS ERROR_TABLE_BASE_zeph

		KRBET_AD_NOTGT KRBET_GC_NOTKT KRBET_GC_TKFIL
		KRBET_GT_PW_BADPW KRBET_GT_PW_KDCERR KRBET_GT_PW_NULL
		KRBET_GT_PW_NULLTKT KRBET_GT_PW_PROT KRBET_INTK_BADPW
		KRBET_INTK_ERR KRBET_INTK_PROT KRBET_INTK_W_NOTALL
		KRBET_KDC_AUTH_EXP KRBET_KDC_BYTE_ORDER KRBET_KDC_GEN_ERR
		KRBET_KDC_NAME_EXP KRBET_KDC_NULL_KEY KRBET_KDC_PKT_VER
		KRBET_KDC_PR_N_UNIQUE KRBET_KDC_PR_UNKNOWN
		KRBET_KDC_P_MKEY_VER KRBET_KDC_SERVICE_EXP
		KRBET_KDC_S_MKEY_VER KRBET_KNAME_FMT KRBET_KRB_RES11
		KRBET_KRB_RES12 KRBET_KRB_RES13 KRBET_KRB_RES14
		KRBET_KRB_RES15 KRBET_KRB_RES16 KRBET_KRB_RES17
		KRBET_KRB_RES18 KRBET_KRB_RES19 KRBET_KRB_RES23
		KRBET_KRB_RES24 KRBET_KRB_RES25 KRBET_KRB_RES27
		KRBET_KRB_RES28 KRBET_KRB_RES29 KRBET_KRB_RES30
		KRBET_KRB_RES44 KRBET_KRB_RES45 KRBET_KRB_RES46
		KRBET_KRB_RES47 KRBET_KRB_RES48 KRBET_KRB_RES49
		KRBET_KRB_RES50 KRBET_KRB_RES58 KRBET_KRB_RES59
		KRBET_KRB_RES60 KRBET_KRB_RES64 KRBET_KRB_RES65
		KRBET_KRB_RES66 KRBET_KRB_RES67 KRBET_KRB_RES68
		KRBET_KRB_RES69 KRBET_KRB_RES72 KRBET_KRB_RES73
		KRBET_KRB_RES74 KRBET_KRB_RES75 KRBET_KSUCCESS
		KRBET_MK_AP_TGTEXP KRBET_NO_TKT_FIL KRBET_RD_AP_BADD
		KRBET_RD_AP_EXP KRBET_RD_AP_INCON KRBET_RD_AP_MODIFIED
		KRBET_RD_AP_MSG_TYPE KRBET_RD_AP_NOT_US KRBET_RD_AP_NYV
		KRBET_RD_AP_ORDER KRBET_RD_AP_REPEAT KRBET_RD_AP_TIME
		KRBET_RD_AP_UNAUTHOR KRBET_RD_AP_UNDEC KRBET_RD_AP_VERSION
		KRBET_SKDC_CANT KRBET_SKDC_RETRY KRBET_TKT_FIL_ACC
		KRBET_TKT_FIL_FMT KRBET_TKT_FIL_INI KRBET_TKT_FIL_LCK
		ERROR_TABLE_BASE_krb

		UNSAFE UNACKED ACKED HMACK HMCTL SERVACK SERVNAK CLIENTACK STAT

		ZAUTH ZNOAUTH ZAUTH_NO ZAUTH_YES ZAUTH_FAILED

		LOCATE_CLASS LOCATE_HIDE LOCATE_LOCATE LOCATE_UNHIDE

		LOGIN_CLASS EXPOSE_NONE EXPOSE_OPSTAFF EXPOSE_REALMVIS
		EXPOSE_REALMANN EXPOSE_NETVIS EXPOSE_NETANN
		LOGIN_USER_LOGIN LOGIN_USER_LOGOUT LOGIN_USER_FLUSH

		PRED_UID PRED_MUID PRED_ALD

		HM_TIMEOUT SRV_TIMEOUT

		ZSRVACK_SENT ZSRVACK_NOTSENT ZSRVACK_FAIL

		ZEPHYR_ADMIN_CLASS

		ZEPHYR_CTL_CLASS ZEPHYR_CTL_REALM REALM_ADD_SUBSCRIBE
		REALM_REQ_SUBSCRIBE REALM_SUBSCRIBE REALM_UNSUBSCRIBE

		ZEPHYR_CTL_CLIENT CLIENT_SUBSCRIBE CLIENT_SUBSCRIBE_NODEFS
		CLIENT_UNSUBSCRIBE CLIENT_CANCELSUB CLIENT_GIMMESUBS
		CLIENT_GIMMEDEFS

		ZEPHYR_CTL_HM HM_BOOT HM_FLUSH HM_DETACH HM_ATTACH

		HM_CTL_CLASS HM_CTL_SERVER SERVER_SHUTDOWN SERVER_PING

		HM_CTL_CLIENT CLIENT_FLUSH CLIENT_NEW_SERVER

		HM_STAT_CLASS HM_STAT_CLIENT HM_GIMMESTATS

		WG_CTL_CLASS WG_CTL_USER USER_REREAD USER_SHUTDOWN USER_STARTUP
		USER_EXIT

		HM_SVCNAME HM_SRV_SVCNAME SERVER_SVCNAME SERVER_SERVICE
		SERVER_INSTANCE

		ZVERSIONHDR ZVERSIONMAJOR ZVERSIONMINOR

		Z_MAXHEADERLEN Z_MAXOTHERFIELDS Z_MAXPKTLEN Z_MAXQLEN
		Z_NUMFIELDS


		ZN_VERSION_FLD ZN_KIND_FLD ZN_UID_FLD ZN_SENDADDR_FLD
		ZN_TIME_FLD ZN_PORT_FLD ZN_AUTH_FLD ZN_TARGETS_FLD
		ZN_OPCODE_FLD ZN_SENDER_FLD ZN_FORMAT_FLD ZN_MULTI_FLD
		ZN_MUID_FLD ZN_OTHER_FLD ZN_MESSAGE_FLD ZN_FROM_FLD

		GetSender GetRealm GetWGPort QLength Pending

		OpenPort ClosePort

		SetFD GetFD

		SetDestAddr GetDestAddr

		ParseExposureLevel InitLocationInfo SetLocation UnsetLocation
		FlushMyLocations

		GetVariable SetVariable UnsetVariable

		LocateUser RequestLocations ParseLocations

		ReadAscii ReadAscii16 ReadAscii32
		MakeAscii MakeAscii16 MakeAscii32

		GetSubscriptions GetDefaultSubscriptions

		SubscribeTo SubscribeToSansDefaults UnsubscribeTo
		CancelSubscriptions

		CompareUID

		ReceiveNotice PeekNotice PeekIfNotice IfNotice CheckIfNotice
		);
%EXPORT_TAGS = (
		'zerr' =>
		[qw(ZERR_AUTHFAIL ZERR_BADFIELD ZERR_BADPKT ZERR_EOF
		    ZERR_FIELDLEN ZERR_HEADERLEN ZERR_HMDEAD ZERR_HMPORT
		    ZERR_ILLVAL ZERR_INTERNAL ZERR_LOGINFAIL ZERR_NOLOCATIONS
		    ZERR_NOMORELOCS ZERR_NOMORESUBSCRIPTIONS ZERR_NONE
		    ZERR_NONOTICE ZERR_NOPORT ZERR_NOSUBSCRIPTIONS ZERR_PKTLEN
		    ZERR_PORTINUSE ZERR_QLEN ZERR_SERVNAK ZERR_TOOMANYSUBS
		    ZERR_VERS ERROR_TABLE_BASE_zeph)],

		'krbet' =>
		[qw(KRBET_AD_NOTGT KRBET_GC_NOTKT KRBET_GC_TKFIL
		    KRBET_GT_PW_BADPW KRBET_GT_PW_KDCERR KRBET_GT_PW_NULL
		    KRBET_GT_PW_NULLTKT KRBET_GT_PW_PROT KRBET_INTK_BADPW
		    KRBET_INTK_ERR KRBET_INTK_PROT KRBET_INTK_W_NOTALL
		    KRBET_KDC_AUTH_EXP KRBET_KDC_BYTE_ORDER KRBET_KDC_GEN_ERR
		    KRBET_KDC_NAME_EXP KRBET_KDC_NULL_KEY KRBET_KDC_PKT_VER
		    KRBET_KDC_PR_N_UNIQUE KRBET_KDC_PR_UNKNOWN
		    KRBET_KDC_P_MKEY_VER KRBET_KDC_SERVICE_EXP
		    KRBET_KDC_S_MKEY_VER KRBET_KNAME_FMT KRBET_KRB_RES11
		    KRBET_KRB_RES12 KRBET_KRB_RES13 KRBET_KRB_RES14
		    KRBET_KRB_RES15 KRBET_KRB_RES16 KRBET_KRB_RES17
		    KRBET_KRB_RES18 KRBET_KRB_RES19 KRBET_KRB_RES23
		    KRBET_KRB_RES24 KRBET_KRB_RES25 KRBET_KRB_RES27
		    KRBET_KRB_RES28 KRBET_KRB_RES29 KRBET_KRB_RES30
		    KRBET_KRB_RES44 KRBET_KRB_RES45 KRBET_KRB_RES46
		    KRBET_KRB_RES47 KRBET_KRB_RES48 KRBET_KRB_RES49
		    KRBET_KRB_RES50 KRBET_KRB_RES58 KRBET_KRB_RES59
		    KRBET_KRB_RES60 KRBET_KRB_RES64 KRBET_KRB_RES65
		    KRBET_KRB_RES66 KRBET_KRB_RES67 KRBET_KRB_RES68
		    KRBET_KRB_RES69 KRBET_KRB_RES72 KRBET_KRB_RES73
		    KRBET_KRB_RES74 KRBET_KRB_RES75 KRBET_KSUCCESS
		    KRBET_MK_AP_TGTEXP KRBET_NO_TKT_FIL KRBET_RD_AP_BADD
		    KRBET_RD_AP_EXP KRBET_RD_AP_INCON KRBET_RD_AP_MODIFIED
		    KRBET_RD_AP_MSG_TYPE KRBET_RD_AP_NOT_US KRBET_RD_AP_NYV
		    KRBET_RD_AP_ORDER KRBET_RD_AP_REPEAT KRBET_RD_AP_TIME
		    KRBET_RD_AP_UNAUTHOR KRBET_RD_AP_UNDEC KRBET_RD_AP_VERSION
		    KRBET_SKDC_CANT KRBET_SKDC_RETRY KRBET_TKT_FIL_ACC
		    KRBET_TKT_FIL_FMT KRBET_TKT_FIL_INI KRBET_TKT_FIL_LCK
		    ERROR_TABLE_BASE_krb)],

		'kind' =>
		[qw(UNSAFE UNACKED ACKED HMACK HMCTL SERVACK SERVNAK CLIENTACK
		    STAT)],

		'auth' =>
		[qw(ZAUTH ZNOAUTH ZAUTH_NO ZAUTH_YES ZAUTH_FAILED)],

		'exposure' =>
		[qw(EXPOSE_NONE EXPOSE_OPSTAFF EXPOSE_REALMVIS EXPOSE_REALMANN
		    EXPOSE_NETVIS EXPOSE_NETANN)],

		'locate' =>
		[qw(LOCATE_CLASS LOCATE_HIDE LOCATE_LOCATE LOCATE_UNHIDE)],

		'login' =>
		[qw(LOGIN_CLASS EXPOSE_NONE EXPOSE_OPSTAFF EXPOSE_REALMVIS
		    EXPOSE_REALMANN EXPOSE_NETVIS EXPOSE_NETANN
		    LOGIN_USER_LOGIN LOGIN_USER_LOGOUT LOGIN_USER_FLUSH)],

		'predicates' =>
		[qw(PRED_UID PRED_MUID PRED_ALD)],

		'timeout' =>
		[qw(HM_TIMEOUT SRV_TIMEOUT)],

		'srv_ack' =>
		[qw(ZSRVACK_SENT ZSRVACK_NOTSENT ZSRVACK_FAIL)],

		'zephyr_admin' =>
		[qw(ZEPHYR_ADMIN_CLASS)],

		'zephyr_realm_ctl' =>
		[qw(ZEPHYR_CTL_CLASS ZEPHYR_CTL_REALM REALM_ADD_SUBSCRIBE
		    REALM_REQ_SUBSCRIBE REALM_SUBSCRIBE REALM_UNSUBSCRIBE)],

		'zephyr_client_ctl' =>
		[qw(ZEPHYR_CTL_CLASS ZEPHYR_CTL_CLIENT CLIENT_SUBSCRIBE
		    CLIENT_SUBSCRIBE_NODEFS CLIENT_UNSUBSCRIBE CLIENT_CANCELSUB
		    CLIENT_GIMMESUBS CLIENT_GIMMEDEFS)],

		'zephyr_hm_ctl' =>
		[qw(ZEPHYR_CTL_HM HM_BOOT HM_FLUSH HM_DETACH HM_ATTACH)],

		'server_hm_ctl' =>
		[qw(HM_CTL_CLASS HM_CTL_SERVER SERVER_SHUTDOWN SERVER_PING)],

		'client_hm_ctl' =>
		[qw(HM_CTL_CLASS HM_CTL_CLIENT CLIENT_FLUSH
		    CLIENT_NEW_SERVER)],

		'hm_stats' =>
		[qw(HM_STAT_CLASS HM_STAT_CLIENT HM_GIMMESTATS)],

		'wg_ctl' =>
		[qw(WG_CTL_CLASS WG_CTL_USER USER_REREAD USER_SHUTDOWN
		    USER_STARTUP USER_EXIT)],

		'svc_names' =>
		[qw(HM_SVCNAME HM_SRV_SVCNAME SERVER_SVCNAME SERVER_SERVICE
		    SERVER_INSTANCE)],

		'version' =>
		[qw(ZVERSIONHDR ZVERSIONMAJOR ZVERSIONMINOR)],

		'max' =>
		[qw(Z_MAXHEADERLEN Z_MAXOTHERFIELDS Z_MAXPKTLEN Z_MAXQLEN
		    Z_NUMFIELDS)],

		'fields' =>
		[qw(ZN_VERSION_FLD ZN_KIND_FLD ZN_UID_FLD ZN_SENDADDR_FLD
		    ZN_TIME_FLD ZN_PORT_FLD ZN_AUTH_FLD ZN_TARGETS_FLD
		    ZN_OPCODE_FLD ZN_SENDER_FLD ZN_FORMAT_FLD ZN_MULTI_FLD
		    ZN_MUID_FLD ZN_OTHER_FLD ZN_MESSAGE_FLD ZN_FROM_FLD)],

		'info' =>
		[qw(GetSender GetRealm GetWGPort QLength Pending)],

		'port' =>
		[qw(OpenPort ClosePort)],

		'fd' =>
		[qw(GetFD SetFD)],

		'destaddr' =>
		[qw(GetDestAddr SetDestAddr)],

		'location' =>
		[qw(ParseExposureLevel InitLocationInfo SetLocation
		    UnsetLocation FlushMyLocations)],

		'variable' =>
		[qw(GetVariable SetVariable UnsetVariable)],

		'locatefcns' =>
		[qw(LocateUser RequestLocations ParseLocations)],

		'ascii' =>
		[qw(ReadAscii ReadAscii16 ReadAscii32
		    MakeAscii MakeAscii16 MakeAscii32)],

		'getsubs' =>
		[qw(GetSubscriptions GetDefaultSubscriptions)],

		'subscription' =>
		[qw(SubscribeTo SubscribeToSansDefaults UnsubscribeTo
		    CancelSubscriptions)],

		'uid' =>
		[qw(CompareUID)],

		'receive' =>
		[qw(ReceiveNotice PeekNotice PeekIfNotice IfNotice
		    CheckIfNotice)],
		);

sub AUTOLOAD {
    # This AUTOLOAD is used to 'autoload' constants from the _symbol()
    # XS function.  If a constant is not found then control is passed
    # to the AUTOLOAD in AutoLoader.

    my $constname;
    ($constname = $AUTOLOAD) =~ s/.*:://;
    my $val = _symbol($constname);
    if ($! != 0) {
	if ($! =~ /Invalid/) {
	    $AutoLoader::AUTOLOAD = $AUTOLOAD;
	    goto &AutoLoader::AUTOLOAD;
	}
	else {
		croak "Your vendor has not defined Zephyr macro $constname";
	}
    }
    eval "sub $AUTOLOAD { \"$val\" }";
    goto &$AUTOLOAD;
}

$error = 0;

bootstrap Zephyr $VERSION;

# Preloaded methods go here.

# Autoload methods go after =cut, and are processed by the autosplit program.

1;
__END__
# Below is the stub of documentation for your module. You better edit it!

=head1 NAME

Zephyr, GetSender, GetRealm, GetWGPort, QLength, Pending, OpenPort, ClosePort, GetFD, SetFD, GetDestAddr, SetDestAddr, ParseExposureLevel, InitLocationInfo, SetLocation, UnsetLocation, FlushMyLocations, GetVariable, SetVariable, UnsetVariable, LocateUser, RequestLocations, ParseLocations, MakeAscii, MakeAscii16, MakeAscii32, ReadAscii, ReadAscii16, ReadAscii32, GetSubscriptions, GetDefaultSubscriptions, SubscribeTo, SubscribeToSansDefaults, UnsubscribeTo, CancelSubscriptions, CompareUID, ReceiveNotice, PeekNotice, PeekIfNotice, IfNotice, CheckIfNotice - Perl extension for interfacing to Zephyr

=head1 SYNOPSIS

  use Zephyr;

  $sender = GetSender();
  $realm = GetRealm();
  $wgport = GetWGPort();
  $qlen = QLength();
  $qlen = Pending();

  $port = OpenPort($myport);
  ClosePort();

  $fd = GetFD();
  SetFD($fd);

  $addr = GetDestAddr();
  SetDestAddr($addr);

  $exposure = ParseExposureLevel($text);

  InitLocationInfo($host, $tty);

  SetLocation($exposure);
  UnsetLocation();
  FlushMyLocations();

  @locations = LocateUser($user, $auth);
  $zald = RequestLocations($user, $auth, $kind);
  @locations = ParseLocations($notice, $zald);

  $value = GetVariable($varname);
  SetVariable($varname, $value);
  UnsetVariable($varname);

  SubscribeTo($port, \@sub);
  SubscribeToSansDefaults($port, \@sub);
  UnsubscribeTo($port, \@sub);
  CancelSubscriptions($port);

  @subs = GetSubscriptions($port);
  @defsubs = GetDefaultSubscriptions();

  $ascii = MakeAscii($data);
  $ascii = MakeAscii16($number);
  $ascii = MakeAscii32($number);

  $data = ReadAscii($ascii);
  $number = ReadAscii16($ascii);
  $number = ReadAscii32($ascii);

  $notice = ReceiveNotice();
  $notice = PeekNotice();
  $notice = PeekIfNotice($predicate, $data);
  $notice = IfNotice($predicate, $data);
  $notice = CheckIfNotice($predicate, $data);

  $isequal = CompareUID($uid1, $uid2);

=head1 DESCRIPTION

The C<Zephyr> Perl module permits direct access to the Zephyr library
from within Perl.  Most of the functionality of that library is
accessible from this module.  Most of notice manipulation is actually
provided by the C<Zephyr::Notice> module, documented in
L<Zephyr::Notice(3)>.

=head2 Utility functions

The C<GetSender()>, C<GetRealm()>, C<GetWGPort()>, C<QLength()>, and
C<Pending()> functions provide basic useful functions that cannot
easily be otherwise classified.

=over 13

=item GetSender()

Returns the name of the individual that Zephyr notices will appear to
be originating from.

=item GetRealm()

Returns the name of the Zephyr realm the library believes itself to be
in.

=item GetWGPort()

Returns the port number of the user's Zephyr windowgram client, if one
is running, or the value -1 if it is unable to determine the port.
This function determines the filename of the port stash file from the
I<WGFILE> environment variable, if it is set, or F</tmp/wg.I<uid>>
otherwise.

=item QLength()

Returns the number of Zephyr notices on the queue awaiting
processing.

=item Pending()

Processes any Zephyr notices that have not yet been received and
returns the result of QLength().

=back

=head2 Port manipulation functions

In order to receive Zephyr notices, it will be necessary to determine
which port the library is using; additionally, it may be desirable to
request the library use a particular port number.  C<OpenPort()> will
open the port given as its argument, or a random port if the argument
is omitted or is zero, and return the port number used, or -1 if an
error occurred; C<ClosePort()> will cause the library to close any
port it has allocated.  (If the C<SetFD()> function has been called,
the library will not attempt to close the external I<fd>.)

=head2 File descriptor manipulation functions

The Zephyr library may also be requested to use a particular file
descriptor allocated by the application through the use of the
C<SetFD()> function.  The application may also obtain the file
descriptor currently in use by the library using the C<GetFD()>
function; this may be particularly useful to applications wishing to
use C<select()> on multiple network sockets.

=head2 Destination address

By default, the Zephyr library attempts to send all notices to the
local Zephyr hostmanager; this address may be obtained using
C<GetDestAddr()>, which returns a sockaddr_in structure that may be
manipulated with the routines in the C<Socket> Perl module (see
L<Socket(3)> for more details).  Applications desiring to send Zephyr
notices to a specific address may pass the desired address to the
C<SetDestAddr()> function.

=head2 Location manipulation functions

Applications may manipulate the Zephyr location database using the
C<SetLocation()>, C<UnsetLocation()>, and C<FlushMyLocations()>
functions.  The C<SetLocation()> function requires an I<exposure>
argument, which may be obtained from the C<ParseExposureLevel()>
function, or one of the following constants: I<EXPOSE_NONE>,
I<EXPOSE_OPSTAFF>, I<EXPOSE_REALMVIS>, I<EXPOSE_REALMANN>,
I<EXPOSE_NETVIS>, or I<EXPOSE_NETANN>.  The I<exposure> argument is
case-sensitive; the C<ParseExposureLevel()> function can convert a
lower-case version to the appropriate value.

Some applications may wish to override the default hostname and
terminal device values used by the location manipulation functions;
this can be done with the C<InitLocationInfo()> function.  (This
function does not exist in older versions of the Zephyr library; if
this is the case, it is emulated by a Perl function which manipulates
the DISPLAY environmental variable; of course, hostname manipulation
is not supported in that environment.)

=head2 User location functions

The current location of a user, as recorded in the Zephyr location
database, can be determined by using the C<LocateUser()> function;
this function takes the fully-qualified user name (that is, the user
name, followed by an "@", followed by the Zephyr realm name) and the
desired authentication level as arguments.  The I<auth> parameter is
optional and may be either one of I<ZAUTH> or I<ZNOAUTH>; if it is not
specified, I<ZAUTH> will be used.

C<LocateUser()> is synchronous, that is, it will block waiting for a
response from the Zephyr server.  As this may be inappropriate for
some applications, the Zephyr library (and this module) also support
asynchronous user location through the C<RequestLocations()>
function.  This function again takes the (fully-qualified) user name
and requests the user's locations.  The I<auth> parameter works in the
same fashion as for C<LocateUser()>; however, the I<kind> of the
resulting message may also be set, if desired, but ordinarily defaults
to I<UNACKED>.

C<RequestLocations()> returns a data object which may be passed to the
notice reception functions in conjunction with the I<PRED_ALD>
predicate; please see the section on "Zephyr Notice Reception" later
in this manual.

Once a notice which matches the ALD emitted by C<RequestLocations()>
has been received, the data actually contained within it may be parsed
by passing the notice and the ALD to the C<ParseLocations()> function.

Both C<LocateUser()> and C<ParseLocations()> return the location data
as an array of array references; each array reference contains three
fields, which are (1) the hostname of the location; (2) the time at
which the location was added to the Zephyr location database; and (3)
the terminal associated with this location.  If these functions are
evaluated in a scalar context, they will return the total number of
locations; if evaluated in a void context, they will have no effect.
Applications should probably restrict themselves to an array context.

=head2 Variable manipulation functions

The Zephyr library has the concept of Zephyr variables, which are
stored in F<$HOME/.zephyr.vars>; the library provides functions to
manipulate these variables.  These functions are C<GetVariable()>,
C<SetVariable()>, and C<UnsetVariable()>.  If the I<value> argument to
C<SetVariable()> is omitted, the result will be the same as if
C<UnsetVariable()> had been called on the variable.

=head2 Subscription manipulation functions

Applications which wish to receive Zephyr notices must first obtain
subscriptions.  The C<SubscribeTo()> and C<SubscribeToSansDefaults()>
functions are provided for this.  C<SubscribeToSansDefaults()> differs
from C<SubscribeTo()> only in that it does not automatically obtain
default subscriptions.  After either of these calls, the resulting
subscriptions will be the union of the previous subscriptions (if
any) and the subscriptions passed to the functions; additionally, if
there were no previous subscriptions, and C<SubscribeTo()> is called,
the default subscriptions for the realm will also be added.

It is also possible to cancel certain subscriptions using the
C<UnsubscribeTo()> function, or to cancel all subscriptions using the
C<CancelSubscriptions()> function.  Applications are encouraged to
call the latter function before exiting, if subscriptions have been
obtained.

For all four of these functions, if no I<port> argument is given, the
port being used by the Zephyr library will be used.  In the case of
C<SubscribeTo()>, C<SubscribeToSansDefaults()>, and
C<UnsubscribeTo()>, the I<port> argument is determined by the fact
that it is not an array reference.

C<SubscribeTo()>, C<SubscribeToSansDefaults()>, and C<UnsubscribeTo()>
accept a list of one or more array references.  Each of these array
contains three fields; these are, in order, (1) the class; (2) the
instance of the class; and (3) the recipient.  The wildcard instance
is the empty instance (i.e., ""); the recipient may be either the
wildcard recipient (again, "") or the user's fully-qualified user name
(as returned by C<GetSender()>).

=head2 Subscription examination functions

The subscriptions currently active for a particular port may be
obtained with the C<GetSubscriptions()> function; if the I<port>
argument is not given, it will default to that currently in use by the
Zephyr library.  The default subscriptions for the current Zephyr
realm may be obtained using C<GetDefaultSubscriptions()> function.
Both of these functions return a list of array references; these
arrays are exactly the same as could be used for input to
C<SubscribeTo()>, C<SubscribeToSansDefaults()>, or C<UnsubscribeTo()>.

Note that the Zephyr servers will convert the text of all subscription
requests to lowercase, in order to support case insensitivity in
subscriptions.  Also note that some Zephyr servers have a bug that
prohibits C<GetDefaultSubscriptions()> from working correctly.

=head2 ASCII encoding and decoding functions

Some applications may wish to send binary data in Zephyr notices; this
is supported through the C<MakeAscii()> and C<ReadAscii()> class of
functions.  C<MakeAscii()> will take a (binary) string and convert it
to an ASCII representation; C<ReadAscii()> performs the complementary
operation.

Many times, the application may wish only to perform operations such
as this on 16-bit or 32-bit integers; these applications may use the
C<MakeAscii16()> and C<MakeAscii32()> functions for encoding these
numbers and C<ReadAscii16()> and C<ReadAscii32()> for decoding them.

The ASCII representation for this data is of the form "0xaabbccdd
0xeeffgghh," where "aa," "bb," "cc," etc. are the hexidecimal
representations of the first, second, third, etc. bytes of the binary
data.

=head2 Zephyr notice reception

There are a total of five notice reception functions.  The simplest of
these is C<ReceiveNotice()>, which will wait until a notice is
received, and will return that notice to the caller.  The first notice
on the internal queue can also be retrieved by C<PeekNotice()>, which
will not remove the notice from the queue.

Sometimes it is desirable to wait for one particular notice to arrive;
the functions which perform this operation will process each notice on
the queue using a B<predicate> function; this function will receive as
arguments the notice upon which it is to operate and an extra
argument; this extra argument will be whatever was passed as the
I<data> argument to these functions.  There are three pre-defined
predicate functions; these are represented by I<PRED_UID>, which
compares the Unique IDs; I<PRED_MUID>, which compares MUIDs; and
I<PRED_ALD>, which will look for a notice containing the results of a
C<RetrieveLocations()>.  Some applications may wish to provide their
own predicates; they may simply pass a function reference as the
I<predicate> argument.

The three functions which require predicates are C<IfNotice()>, which
will wait for the notice if it is not already on the queue;
C<CheckIfNotice()>, which will return immediately if there is no
suitable notice on the queue; and C<PeekIfNotice()>, which will return
a notice if it is on the queue, but will not remove it from the queue.

Each of these functions returns an object in the C<Zephyr::Notice>
class; please see L<Zephyr::Notice(3)> for more details about the
operations that may be performed on these objects.

=head2 Zephyr unique ID comparision

Each notice contains a Unique ID, which may be obtained using the
C<getUID()> method on the notice (please see L<Zephyr::Notice(3)> for
more details).  These UIDs may be compared using the C<CompareUID()>
function, which will return I<TRUE> if they match or I<FALSE>
otherwise.

=head2 Exported symbol tags

By default, no symbols are exported, but several tags are defined;
this interface may change in the future; suggestions are welcome.  The
defined tags and what symbols they import are defined as follows:

=over 10

=item zerr

Zephyr error code values, such as ZERR_NONE.

=item krbet

The Kerberos (V4) error code values; provided for convenience.

=item kind

Zephyr notice kind values, such as ACKED, UNACKED, or UNSAFE.

=item auth

Authentication codes, such as ZAUTH and ZAUTH_YES.

=item exposure

Exposure levels, from EXPOSE_NONE to EXPOSE_NETANN.

=item locate

Constants used internally for location manipulation functions, such as
LOCATE_CLASS; most applications will not need to use any of these
codes, but they are provided for completeness.

=item login

Constants used for sending login zephyrs; this may be useful to
applications which wish to use the information contained in the login
zephyrs.  This tag also exports the exposure levels.

=item predicates

Predicate values that may be passed to the Zephyr receiving functions,
which are documented above.

=item timeout

Various timeouts defined in zephyr/zephyr.h.

=item srv_ack

Strings which may be contained within a SERVACK indicating the success
or failure of a particular notice.

=item zephyr_admin

The Zephyr server administration class; this is included only for the
sake of completeness.

=item zephyr_realm_ctl

Zephyr realm subscription constants; these may not be available for
all sites.

=item zephyr_client_ctl

Zephyr client request constants; these constants are used for
subscription and unsubscription messages, subscription retrieval, and
subscription cancellation messages.  These values are included only
for completeness; applications should use the subscription functions
in this package for this functionality.

=item zephyr_hm_ctl

Zephyr host manager control messages which the host manager may send
to the server; these values are included only for completeness.

=item server_hm_ctl

Zephyr host manager control messages which the Zephyr server may send
to host managers; again, these values are included only for
completeness.

=item client_hm_ctl

Zephyr host manager control messages which clients may send to host
managers; these values are sent by clients to request certain actions
from the host manager, such as selecting a new server.

=item hm_stats

Zephyr host manager statistics request messages.

=item wg_ctl

Zephyr windowgram client control messages which may be generated by
B<zctl>; see L<zctl(1)>, and specifically the section on B<wg_*>
subcommands, for more information.  Zephyr receiving clients may wish
to implement actions for these control messages, so that they may be
controlled through B<zctl>.  Note that USER_EXIT may not be defined at
all sites.

=item svc_names

Constants specifying the service names used for Kerberos
authentication and for correct destination port selection.

=item version

Constants specifying the version of the Zephyr protocol being used by
the Zephyr library with which this module was linked when it was
built.

=item max

Various maximum values used internally by the library, including
Z_MAXOTHERFIELDS.

=item fields

Field codes which may be passed to the C<set()> or C<new()> methods,
defined in L<Zephyr::Notice(3)>.

=item info

This defines the information routine functions, such as
C<GetSender()>.

=item port

C<OpenPort()> and C<ClosePort()>.

=item fd

C<GetFD()> and C<ClosePort()>.

=item destaddr

C<GetDestAddr()> and C<SetDestAddr()>.

=item location

The location manipulation functions, such as C<SetLocation()>.

=item variable

The Zephyr variable manipulation functions, such as C<GetVariable()>.

=item locatefcns

The Zephyr user location functions, such as C<LocateUser()>.

=item ascii

The ASCII encoding/decoding functions.

=item getsubs

The subscription retrieval functions.

=item subscription

The subscription manipulation functions, such as C<SubscribeTo()>.

=item uid

The C<CompareUID()> function.

=item receive

The Zephyr notice reception functions, such as C<ReceiveNotice()>.

=back

=head1 ERRORS

These functions return I<FALSE> or illegal values in the event of an
error and set C<$Zephyr::error> to contain the appropriate numerical
values and the associated error message.  Possible values include UNIX
error messages, error messages from the Kerberos V4 library, and of
course from the Zephyr library; symbolic values for the latter two may
be included using the B<krbet> and B<zerr> tags.

=head1 ENVIRONMENT

=over 8

=item WGFILE

Specifies the name of the file containing the port number currently
being used by B<zwgc>; if this is not set, it defaults to
F</tmp/wg.I<uid>>

=back

=head1 FILES

=over 20

=item F<$HOME/.zephyr.vars>

Contains the user's Zephyr variables.

=back

=head1 AUTHOR

Kevin L. Mitchell, <klmitch@mit.edu>

=head1 SEE ALSO

perl(1), zephyr(1), zwgc(1), zctl(1), Socket(3), Zephyr::Notice(3)

=head1 BUGS

The C<GetDefaultSubscriptions()> may not work properly at all sites,
due to a Zephyr server bug.

=head1 RESTRICTIONS

Zephyr is Copyright (c) 1987,1988,1989 by the Massachusetts Institute
of Technology.  All Rights Reserved.

See L<zephyr(1)> for the terms and conditions for redistribution of
that package.

=cut

sub InitLocationInfo {
    my ($host, $tty) = @_;

    # this is what you'd do in 8.1 to set the tty...can't do anything
    # about the hostname field, though.
    $ENV{'DISPLAY'} = $tty; 
    return 1;
}

sub ParseExposureLevel {
    my ($text) = @_;

    return uc($text);
}
