package Zephyr::Notice;

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

require Exporter;
require DynaLoader;
require AutoLoader;
require Zephyr;

@ISA = qw(Exporter DynaLoader);
# 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 = qw(

);
$VERSION = $Zephyr::VERSION; # we track Zephyr's version number

# 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::Notice, new, wasSent, wasReceived, isImmutable, send, set, get, setKind, setPort, setAuth, setTargets, setOpcode, setSender, setFormat, setOther, setMessage, getVersion, getKind, getUID, getSendAddr, getTime, getPort, getAuth, getTargets, getOpcode, getSender, getFormat, getMUID, getOther, getMessage, getFrom - Perl class package for Zephyr notices

=head1 SYNOPSIS

  use Zephyr;

  $notice = new Zephyr::Notice();

  $sent = $notice->wasSent();
  $recv = $notice->wasReceived();
  $immutable = $notice->isImmutable;

  $notice->send();

  $notice->set();
  %notice = $notice->get();

  $notice->setKind();
  $notice->setPort();
  $notice->setAuth();
  $notice->setTargets();
  $notice->setOpcode();
  $notice->setSender();
  $notice->setFormat();
  $notice->setOther();
  $notice->setMessage();

  $version = $notice->getVersion();
  $kind = $notice->getKind();
  $UID = $notice->getUID();
  $sendaddr = $notice->getSendAddr();
  $time = $notice->getTime();
  $port = $notice->getPort();
  $auth = $notice->getAuth();
  @targets = $notice->getTargets();
  $opcode = $notice->getOpcode();
  $sender = $notice->getSender();
  $format = $notice->getFormat();
  $multiUID = $notice->getMUID();
  @other = $notice->getOther();
  @message = $notice->getMessage();
  $from = $notice->getFrom();

=head1 DESCRIPTION

A B<notice> object is an object within the C<Zephyr::Notice> class;
one may be allocated by the C<new()> method, or by the notice
reception functions in the C<Zephyr> package; see L<Zephyr(3)> for
more details about these functions.

A B<notice> may be in one of three states; it may be in the
I<RECEIVED> state, the I<SENT> state, or in the I<NULL> state.  If a
notice is in either the I<RECEIVED> or I<SENT> states, it may not be
modified, and is thus I<immutable>.  Three methods are provided to
determine what state a particular notice is in:  the C<wasSent()>
method will return I<TRUE> if the messages is in the I<SENT> state;
the C<wasReceived()> method will return I<TRUE> if the message is in
the I<RECEIVED> state; and the C<isImmutable()> method returns I<TRUE>
if the notice is in either of these two states, or I<FALSE> otherwise.

The C<new()> method allocates a B<notice> in the I<NULL> state,
permitting the B<notice> to be manipulated by the C<set*()> family of
functions, as well as permitting the C<send()> method to be called on
the B<notice>.  The C<send()> method will cause the B<notice>, if it
is I<not> immutable, to be sent and will set it into the I<SENT>
state.

Various characteristics of the B<notice>, such as the message
contents, may be obtained or manipulated using the C<set*()> and
C<get*()> family of methods.  The C<set()> method (and optionally the
C<new()> method) take a list of key-value pairs; the C<get()> method
returns such a list.  The available keys, along with the individual
methods, are documented below.

=head2 Version field

The Zephyr protocol version a particular B<notice> was sent with may
be obtained using the C<getVersion()> method; the corresponding key is
ZN_VERSION_FLD ("version").  Note that this field is only available
for B<notice>s in the I<RECEIVED> or I<SENT> states; also note that it
is not possible to set this field.

=head2 Kind field

The C<getKind()> method returns the message kind, a numerical constant
which can take the following values:  UNSAFE, UNACKED, ACKED, HMACK,
HMCTL, SERVACK, SERVNAK, CLIENTACK, and STAT.  The corresponding key
is ZN_KIND_FLD ("kind").  To set a B<notice>'s kind, use the
C<setKind()> method or use the C<set()> method with the appropriate
key.

=head2 Unique ID field

Each B<notice> has a unique ID; this UID may be obtained via
C<getUID()> for B<notice>s which have been sent with C<send()> or for
B<notice>s which have been received.  The appropriate key value for
C<get()> is ZN_UID_FLD ("uid").  Applications should treat the value
thus returned as being opaque.  This field may not be set.

Two UIDs may be compared using C<CompareUID()>; see L<Zephyr(3)> for
more details about this function.

=head2 Sender address field

Notices which have been sent or received also have an associated
sender address, which may be obtained using the C<getSendAddr()>
method; the corresponding key value for C<get()> is ZN_SENDADDR_FLD
("sendaddr").  This field may not be set.

=head2 Time field

The time at which a particular B<notice> was sent may be obtained
using the C<getTime()> method; the integer portion of the number
returned is the number of seconds since the (UNIX) epoch.  The key
value used for C<get()> is ZN_TIME_FLD ("time"); again, this field may
not be set, and is only valid for B<notice>s which have been sent or
received.

=head2 Port field

Each B<notice> includes the port number it was sent from; this
information may be retrieved using C<getPort()>.  Applications are
also permitted to set this field to arbitrary values using
C<setPort()>; if this field is not set or is set to 0, the Zephyr
library will use the currently allocated port number.  The
corresponding key value is ZN_PORT_FLD ("port").

=head2 Authentication field

The authentication field is an overloaded field; for notices which
have been received, the C<getAuth()> method will return one of
ZAUTH_YES (for authenticated notices), ZAUTH_NOAUTH (for
unauthenticated notices), and ZAUTH_FORGED (for authenticated notices
which have failed verification).  For notices which have not been
received, C<getAuth()> will return one of ZAUTH or ZNOAUTH, depending
on whether or not authentication will be (or was) attempted for the
notice; this normally defaults to ZAUTH.  The authentication status in
this case may be set using C<setAuth()>; the associated key value for
the C<set()> and C<get()> methods is ZN_AUTH_FLD ("auth").

=head2 Targets

Notices have associated target data; to get the targetting data on a
notice, use the C<getTargets()> method.  This method will return a
list of array references; each one of these references contains as its
first field the B<class> the notice went to; the second is the
B<instance> of the class, and the third is the B<recipient>.  For
received notices, only one target value will be returned, and
B<recipient> must be either "" (the "wildcard" recipient) or must be
the same as that returned by C<GetSender()>; please see L<Zephyr(3)>
for more details about this function.

Targetting information can be set using C<setTargets()>, or using the
ZN_TARGETS_FLD ("targets") key value to C<set()>; in both cases, a
list of targets is passed (of course, in the latter case, this must be
an array reference).  If one of these target values is a simple
string, it will be interpreted as a recipient, and the default class
("message") and class instance ("personal") will be used for that
target.  If this target is an array reference containing exactly one
element, that element will be interpreted as an instance of the
default class, and the default recipient ("" or the "wildcard"
recipient); if it contains two elements, the first will be interpreted
as a class and the second as an instance of that class, and the
recipient will again be set to the default; if there are three
elements, the first two will be interpreted as for the two-element
case, and the final element will be interpreted as a recipient.

If the C<send()> method is invoked on a notice which has not had any
targetting data set, the notice will be be sent to the default
instance of the default class, with the recipient set to the result of
C<GetSender()>.

=head2 Opcode field

Each notice has an associated opcode, which may be obtained using the
C<getOpcode()> method, or the C<get()> method using the ZN_OPCODE_FLD
("opcode") key.  If the application does not set an opcode (using
the C<setOpcode()> method) before sending the notice, it will be set
to the null opcode, "".

=head2 Sender field

An application may obtain the name of the sender of a notice using the
C<getSender()> method; the sender field may also be set using the
C<setSender()> method, but users must realize that authentication will
override this value.  The associated C<set()>/C<get()> key is
ZN_SENDER_FLD ("sender").

=head2 Default format field

Each notice must have a default format, indicating how the notice will
be formatted by the recipient, if the recipient does not do any
formatting of its own.  If one is not set, using the C<setFormat()>
method, it will default to a reasonable value; this default depends on
authentication and on the number of fields in the message.  The format
that would be used if this message was to be sent immediately may be
obtained using the C<getFormat()> method on a not-yet-sent notice;
note that if the authentication or the message are modified, this may
modify the default format used.  Of course, if an application
explicitly sets this field, that value will be used.  The associated
C<set()>/C<get()> key is ZN_FORMAT_FLD ("format").

=head2 Multi UID field

The multi-UID field is another unique identifier similiar to the UID
field, described above; its value may be obtained using the
C<getMUID()> method, and the associated key value is ZN_FORMAT_MUID
("muid").  The author has not yet determined the actual use of this
field within the Zephyr library.

=head2 Other header fields

The Zephyr notice also contains a number of optional headers which may
be set using the C<setOther()> method.  This method takes a list of
strings and stores as many as Z_MAXOTHERFIELDS of them in the notice;
the fields may be retrieved from the notice using the C<getOther()>
method; the associated C<set()>/C<get()> key is ZN_OTHER_FLD
("other").

=head2 Message fields

One of the most important parts of a Zephyr notice is, of course, the
message.  To the application, each message consists of a number of
message fields (in the actual Zephyr packet, each field is terminated
with an ASCII nul character and immediately followed by the next
field, if any).  For comparison, the standard B<zwrite> utility sends
message with at most two fields; the first field is the signature, and
the second field is the actual message.  (If the signature is omitted,
the message is placed in the first field in its place.)

The message may be retrieved from a notice using the C<getMessage()>
method, and may be set using C<setMessage()>; the corresponding
C<set()>/C<get()> key is ZN_MESSAGE_FLD ("message").

=head2 From field

This field is only set for messages which have been received; it may
be obtained using C<getFrom()>, and the return value will be a
sockaddr_in, which may be manipulated using the routines in the
C<Socket> Perl module (see L<Socket(3)> for more details).  The
associated C<get()> key is ZN_FROM_FLD ("from").

=head1 ERRORS

All of these functions return invalid values and set C<$!> on error.

=head1 AUTHOR

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

=head1 SEE ALSO

perl(1), zephyr(1), Socket(3), Zephyr(3)

=head1 RESTRICTIONS

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

See the zephyr(1) manpage for the terms and conditions for
redistribution of that package.

=cut
#' to make fontlock to the right thing :/  will anyone ever make emacs
# DoSomethingIntelligent(tm) with embedded pod documentation?

# not currently implemented
sub setPacket {
    my $self = shift;
    return $self->set('packet', @_);
}

# not currently implemented
sub setVersion {
    my $self = shift;
    return $self->set('version', @_);
}

sub setKind {
    my $self = shift;
    return $self->set('kind', $_[1]);
}

# not currently implemented
sub setUID {
    my $self = shift;
    return $self->set('uid', @_);
}

# not currently implemented
sub setSendAddr {
    my $self = shift;
    return $self->set('sendaddr', @_);
}

# not currently implemented
sub setTime {
    my $self = shift;
    return $self->set('time', @_);
}

sub setPort {
    my $self = shift;
    return $self->set('port', $_[1]);
}

sub setAuth {
    my $self = shift;
    return $self->set('auth', $_[1]);
}

sub setTargets {
    my $self = shift;
    return $self->set('targets', [ @_ ]);
}

sub setOpcode {
    my $self = shift;
    return $self->set('opcode', $_[1]);
}

sub setSender {
    my $self = shift;
    return $self->set('sender', $_[1]);
}

sub setFormat {
    my $self = shift;
    return $self->set('format', $_[1]);
}

# not currently implemented
sub setMulti {
    my $self = shift;
    return $self->set('multi', @_);
}

# not currently implemented
sub setMUID {
    my $self = shift;
    return $self->set('muid', @_);
}

sub setOther {
    my $self = shift;
    return $self->set('other', [ @_ ]);
}

sub setMessage {
    my $self = shift;
    return $self->set('message', [ @_ ]);
}

# not currently implemented
sub setFrom {
    my $self = shift;
    return $self->set('from', @_);
}

sub get {
    my $self = shift;
    return (
	'packet'	=> $self->getPacket(1),
	'version'	=> $self->getVersion(1),
	'kind'		=> $self->getKind(1),
	'uid'		=> $self->getUID(1),
	'sendaddr'	=> $self->getSendAddr(1),
	'time'		=> $self->getTime(1),
	'port'		=> $self->getPort(1),
	'auth'		=> $self->getAuth(1),
	'targets'	=> [ $self->getTargets(1) ],
	'opcode'	=> $self->getOpcode(1),
	'sender'	=> $self->getSender(1),
	'format'	=> $self->getFormat(1),
	'multi'		=> $self->getMulti(1),
	'muid'		=> $self->getMUID(1),
	'other'		=> [ $self->getOther(1) ],
	'message'	=> [ $self->getMessage(1) ],
	'from'		=> $self->getFrom(1),
    );
}
