NAME
    Net::AOLIM - Object-Oriented interface to the AOL Instant Messenger TOC
    client protocol

SYNOPSIS
    The really short form:

        use Net::AOLIM;
        $aim = Net::AOLIM->new('username' => $user,
                               'password' => $pass,
                               'callback' => \&handler);

        $aim->signon;

        $aim->toc_send_im($destuser, $message);

NOTES
    Error conditions will be stored in $main::IM_ERR, with any arguments to
    the error condition stored in $main::IM_ERR_ARGS.

    The hash %Net::AOLIM::ERROR_MSGS contains english translations of all of
    the error messages that are either internal to the module or particular
    to the TOC protocol.

    Errors may take arguments indicating a more specific failure condition.
    In this case, they will either be stored in $main::IM_ERR_ARGS or they
    will come from the server ERROR message. To insert the arguments in the
    proper place, use a construct similar to:

        $ERROR = $Net::AOLIM::ERROR_MSGS{$IM_ERR};
        $ERROR =~ s/\$ERR_ARG/$IM_ERR_ARGS/g;

    This assumes that the error code is stored in $IM_ERR and the error
    argument is stored in $IM_ERR_ARGS.

    All methods will return undef on error, and will set $main::IM_ERR and
    $main::IM_ERR_ARGS as appropriate.

    It seems that TOC servers won't acknowledge a login unless at least one
    buddy is added before toc_init_done is sent. Thus, as of version 1.6,
    Net::AOLIM will add the current user to group "Me" if you don't create
    your buddy list before calling signon(). Don't bother removing this if
    you have added your buddies; it'll automagically disappear.

DESCRIPTION
    This section documents every member function of the Net::AOLIM class.

  $Net::AOLIM->new()
    This is the Net::AOLIM Constructor.

    It should be called with following arguments (items with default values
    are optional):

        'username' => login
        'password' => password
        'callback' => \&callbackfunction
        'server' => servername (default toc.oscar.aol.com)
        'port' => port number (default 1234)
        'allow_srv_settings' => <1 | 0> (default 1)
        'login_server' => login server (default login.oscar.aol.com)
        'login_port' => login port (default 5198)
        'login_timeout' => timeout in seconds to wait for a response to the
                           toc_signon packet.  Default is 0 (infinite)
        'aim_agent' => agentname (max 200 char) 
                    Default is AOLIM:$Version VERSION$
                    There have been some reports that changing this 
                    may cause TOC servers to stop responding to signon 
                    requests

    callback is the callback function that handles incoming data from the
    server (already digested into command plus args). This is the meat of
    the client program.

    allow_srv_settings is a boolean that dictates whether the object should
    modify the user configuration on the server. If allow_srv_settings is
    false, the server settings will be ignored and will not be modified.
    Otherwise, the server settings will be read in and parsed, and will be
    modified by calls that modify the buddy list.

    aim_agent is the name of the client program as reported to the TOC
    server

    Returns a blessed instantiation of Net::AOLIM.

  $aim->signon()
    Call this after calling "new()" and after setting initial buddy listings
    with "add_buddies()", "im_permit()", "im_deny()", "im_permit_all()", and
    "im_deny_all()" as necessary.

    Returns undef on failure, setting $main::IM_ERR and $main::IM_ERR_ARGS
    as appropriate. Returns 0 on success.

    This function is also called every time we receive a SIGN_ON packet from
    the server. This is because we are required to react in a specific way
    to the SIGN_ON packet, and this method contains all necessary
    functionality. We should only receive SIGN_ON while connected if we have
    first received a PAUSE (see the TOC(7) documentation included with this
    package for details of how PAUSE works).

  $aim->read_sflap_packet()
    This method returns data from a single waiting SFLAP packet on the
    server socket. The returned value is the payload section of the SFLAP
    packet which is completely unparsed.

    Most users will never need to call this method.

    For more information, see ROLLING YOUR OWN below and the TOC(7) manpage.

  $aim->send_sflap_packet($type, $data, $formatted, $noterm)
    This method sends an SFLAP packet to the server.

    $type is one of the SFLAP types (see TOC(7)).

    $data is the payload to send.

    If $formatted evaluates to true, the data is assumed to be the
    completely formed payload of the SFLAP packet; otherwise, the payload
    will be packed as necessary. This defaults to 0. In either case, the
    header is prepended to the payload.

    If $noterm evaluates to true, the payload will not be terminated with a
    '\0'. Otherwise, it will be terminated. If $formatted is true, this
    option is ignored and no null is appended. This defaults to 0.

    Most users will never need to use this method.

    For more information, see TOC(7) and ROLLING YOUR OWN below.

  $aim->srv_socket()
    This method returns a reference to the socket to which the server is
    connected. It must be dereferenced before it can be used. Thus:

    "$foo = $aim->srv_socket();" "recv($$foo, $recv_buffer, $length,
    $flags);"

    Most users will never need to directly access the server socket.

    For more information, see the TOC(7) manpage and ROLLING YOUR OWN below.

  $aim->pw_roast($password)
    This method returns the 'roasted' version of a password. A roasted
    password is the original password XORed with the roast string 'Tic/Toc'
    (which is repeated until the length is the same as the password length).

    This method is called automatically in $aim->signon. Most users will
    never need this method.

    For more information, see the TOC(7) manpage and ROLLING YOUR OWN below.

  $aim->norm_uname($username)
    This method returns the 'normalized' version of a username. A normalized
    username has all spaces removed and is all lowercase. All usernames sent
    to the server should be normalized first if they are an argument to a
    TOC command.

    All methods in this class automatically normalize username arguments to
    the server; thus, most users will never use this method.

    For more information, see the TOC(7) manpage and ROLLING YOUR OWN below.

  $aim->toc_format_msg($command[, $arg1[, arg2[, ...]]])
    This method formats a message properly for sending to the TOC server.
    That is, it is escaped and quoted, and the fields are appended with
    spaces as specified by the protocol.

    Note that all methods in this class automatically format messages
    appropriately; most users will never need to call this method.

    See TOC(7) and ROLLING YOUR OWN below.

  $aim->toc_format_login_msg($command[, $arg1[, arg2[, ...]]])
    This method formats a login message properly for sending to the TOC
    server. That is, all fields are escaped, but only the user_agent field
    is quoted. Fields are separated with spaces as specified in the TOC
    protocol.

    Note that the login procedure calls this function automatically; the
    user will probably never need to use it.

    See TOC(7) and ROLLING YOUR OWN below.

  $aim->toc_send_im($uname, $msg, $auto)
    This method sends an IM message $msg to the user specified by $uname.
    The third argument indicates whether or not this IM should be sent as an
    autoreply, which may produce different behavior from the remote client
    (but has no direct effect on the content of the IM).

  $aim->add_buddies($group, $buddy1[, $buddy2[, ...]])
    This method, which should only be called before signon(), adds buddies
    to the initial local buddy list in group $group. Once "signon()" is
    called, use add_online_buddies instead.

  $aim->add_online_buddies($group, $buddy1[, $buddy2[, ...]])
    This method takes the same arguments as "add_buddies()", but is intended
    for use after "signon()" has been called.

    If allow_srv_settings is true (see "new()"), it will also set the
    settings on the server to the new settings.

  $aim->remove_online_buddies($buddy1[, $buddy2[, ...]])
    Removes all arguments from the buddy list (removes from all groups).

    If allow_srv_settings is true (see "new()"), it will also set the
    settings on the server to the new settings.

  $aim->current_buddies(\%buddyhash)
    This method fills the hash referenced by "\%buddyhash" with the
    currently stored buddy information. Each key in the returned hash is the
    name of a buddy group, and the corresponding value is a list of the
    members of that group.

  $aim->current_permits()
    This method takes no arguments. It returns the current 'permit' list.

  $aim->current_denies()
    This method takes no arguments. It returns the current 'deny' list.

  $aim->im_permit($user1[, $user2[, ...]])
    This method should only be called before signon(). It adds all arguments
    to the current permit list and deletes the current deny list. It also
    sets the permit mode to 'permit some'.

    If you would like to do this while online, use the "add_im_permit()"
    method instead.

  $aim->im_deny($user1[, $user2[, ...]])
    This method should only be called before signon(). It adds all arguments
    to the current deny list and deletes the current permit list. It also
    sets the permit mode to 'deny some'.

    If you would like to do this while online, use the "add_im_permit()"
    method instead.

  $aim->add_im_permit($user1[, $user2[, ...]])
    This is the method that should be called if you are online and wish to
    add users to the permit list. It will, as a consequence, delete the
    current deny list and set the current mode to 'permit some'.

  $aim->add_im_deny($user1[, $user2[, ...]])
    This is the method that should be used if you are online and wish to add
    users to the deny list. It will, as a consequence, delete the current
    permit list and set the current mode to 'deny some'.

  $aim->im_deny_all()
    This method should be called only before signon(). It will delete both
    the permit and deny list and set the mode to 'deny all'.

  $aim->im_permit_all()
    This method should be called only before signon(). It will delete both
    the permit and deny list and set the mode to 'permit all'.

  $aim->add_im_deny_all()
    This is the method that should be used if you are online and wish to go
    into 'deny all' mode. It will also delete both the permit and deny
    lists.

  $aim->add_im_permit_all()
    This is the method that should be used if you are online and wish to go
    into 'permit all' mode. It will also delete both the permit and deny
    lists.

  $aim->toc_evil($user, $anon)
    This method will apply 'evil' to the specified user $user. If $anon
    evaluates to true, the evil will be done anonymously.

  $aim->toc_chat_join($exchange, $room_name)
    This method will join the chat room specified by $exchange and
    $room_name. Currently, the only valid value for $exchange is 4.

    See the TOC(7) manpage included with this package for more information
    on chatting.

  $aim->toc_chat_send($roomid, $message)
    This method will send the message $message to the room $roomid (which
    should be the room ID provided by the server in response to a
    toc_chat_join or toc_accept_invite).

    You will receive this message back from the server as well, so your UI
    does not have to handle this message in a special way.

  $aim->toc_chat_whisper($roomid, $dstuser, $message)
    This method sends the message $message to $dstuser in the room $roomid.

    The server will not send you a copy of this message, so your user
    interface should have a special case for displaying outgoing whispers.

  $aim->toc_chat_evil($roomid, $dstuser, $anon)
    This will apply evil to the user $dstuser in room $room. If $anon
    evaluates to true, it will be applied anonymously.

    Please note that this functionality is currently disabled by the TOC
    servers.

  $aim->toc_chat_invite($roomid, $msgtext, $buddy1[, $buddy2[, ...]])
    This method will invite all users "$buddy1..$buddyN" to room $roomid
    with invitation text $msgtext.

  $aim->toc_chat_leave($roomid)
    This method will notify the server that you have left room $roomid.

  $aim->toc_chat_accept($roomid)
    This method accepts a chat invitation to room $roomid. You do not have
    to send a "toc_chat_join()" message if you have been invited and accept
    with this method.

  $aim->toc_get_info($username)
    This method requests info on user $username. See TOC(7) for more
    information on what the server returns.

  $aim->toc_set_info($info)
    This method sets the information for the current user to the ASCII text
    (HTML formatted) contained in $info.

  $aim->toc_set_away($msg)
    This method sets or unsets the away message. If $msg is undefined, away
    is unset. Otherwise, away is set with the message in $msg.

  $aim->toc_get_dir($username)
    This method sends a request to the server for directory information on
    $username. See TOC(7) for information on what the server will return.

  $aim->toc_set_dir($userinfo)
    This method sets the information on the current user to the string
    provided as $userinfo. See TOC(7) for more information on the format of
    the $userinfo string.

  $aim->toc_dir_search($searchstr)
    This method will search the directory using $searchstr. See TOC(7) for
    more information on how this string should look.

  $aim->toc_set_idle($seconds)
    This method sets the number of seconds that the client has been idle. If
    it is 0, the idle is cleared. Otherwise, the idle is set and the server
    will continue to count up the idle time (thus, you need only call
    "idle()" once in order to become idle).

  $aim->ui_add_fh($filehandle, \&callback)
    This method will add a filehandle to the "select()" loop that will be
    called with "ui_dataget()". If information is found to be on that
    filehandle, the callback will be executed. It is the responsibility of
    the callback to read the data off the socket.

    As always, the use of buffered IO on filehandles being select()ed is
    unreliable at best. Avoid the use of read(), <FH>, and print(); instead,
    use sysread() and syswrite()

  $aim->ui_del_fh($filehandle)
    The filehandle $filehandle will be removed from the "select()" loop and
    it will no longer be checked for input nor its callback activated.

  $aim->ui_all_fh()
    This method returns a list of all filehandles currently in the
    "select()" loop.

  $aim->ui_exists_fh($filehandle)
    This method will return true if $filehandle is in the select loop.
    Otherwise, it will return undefined.

  $aim->ui_set_callback(\&callback)
    This method will change the callback function for the server socket to
    the method referenced by \&callback. This allows you to change the
    callback from the one specified when the object was created. (Imagine
    the possibilities--dynamically created callback functions using
    "eval()"... mmmm...)

  $aim->ui_get_callback($filehandle)
    This method returns a reference to the callback associated with
    $filehandle, or the callback associated with the server socket if
    $filehandle is undefined.

  $aim->ui_dataget($timeout)
    This is the workhorse method in this object. When this method is called,
    it will go through a single "select()" loop to find if any filehandles
    are ready for reading. If $timeout is defined, the "select()" timeout
    will be that number of seconds (fractions are OK). Otherwise, "select()"
    will block.

    For each filehandle that is ready for reading, this function will call
    the appropriate callback function. It is the responsibility of the
    callback to read the data off the filehandle and handle it
    appropriately. The exception to this rule is the server socket, whose
    data will be read and passed to the server socket callback function. All
    pasrsing of data from the server into edible chunks will be done for you
    before the server socket callback function is called. From there, it is
    up to to the client program to parse the server responses appropriately.
    They will be passed such that each field in the server response is one
    argument to the callback (the number of arguments will be correct). For
    more information on the information coming from the server, see TOC(7).

    This method returns undef on an error (including errors from callbacks,
    which should be signified by returning undef) and returns the number of
    filehandles that were read otherwise.

ROLLING YOUR OWN
    This section deals with usage that deals directly with the server
    connection and bypasses the ui_* interface and/or the toc_* interface.
    If you are happy calling ui_dataget et al., do not bother reading this
    section. If, however, you plan not to use the provided interfaces, or if
    you want to know more of what is going on, continue on.

    First of all, if you do not plan to use the provided interface to the
    server socket, you will need to be able to access the server socket
    directly. In order to do this, use $aim->srv_socket:

        $srv_sock = $aim->srv_socket;

    This will return a pointer to the socket. You will need to dereference
    it in order to use it.

    In general, however, even if you are rolling your own, you will probably
    not need to use "recv()" or the like. "read_sflap_packet()" will handle
    unwrapping the data coming from the server and will return the payload
    of the packet as a single scalar. Using this will give you the data
    coming from the server in a form that you can "split()" to get the
    message and its arguments. In order to facilitate such splitting,
    %Net::AOLIM::SERVER_MSG_ARGS is supplied. For each valid server message,
    $Net::AOLIM::SERVER_MSG_ARGS{$msg} will return one less than the proper
    number of splits to perform on the data coming from the server. The
    intended use is such:

        ($msg, $rest) = split(/:/, $aim->read_sflap_packet(), 2);
        @msg_args = split(/:/, $rest, $Net::AOLIM::SERVER_MSG_ARGS{$msg});

    Now you have the server message in $msg and the arguments in @msg_args.

    To send packets to the server without having to worry about making SFLAP
    packets, use "send_sflap_packet()". If you have a string to send to the
    server (which is not formatted), you would use:

        $aim->send_sflap_packet($SFLAP_TYPE_DATA, $message, 0, 0);

    The SFLAP types (listed in TOC(7) are:

        $SFLAP_TYPE_SIGNON
        $SFLAP_TYPE_DATA
        $SFLAP_TYPE_ERROR
        $SFLAP_TYPE_SIGNOFF
        $SFLAP_TYPE_KEEPALIVE

    Most of the time you will use $SFLAP_TYPE_DATA.

    If you want to roll your own messages, read the code for
    "send_sflap_packet()" and you should be able to figure it out. Note that
    the header is always supplied by "send_sflap_packet()". Specifying
    "formatted" will only make "send_sflap_data()" assume that $message is a
    preformatted payload. Specifying $noterm will prevent
    "send_sflap_packet()" from adding a trailing '\0' to the payload. If it
    is already formatted, "send_sflap_packet" will ignore $noterm.

    Messages sent to the server should be escaped and formatted properly as
    defined in TOC(7). "$aim->toc_format_msg" will do just this; supply it
    with the TOC command and the arguments to the TOC command (each as
    separate strings) and it will return a single string that is formatted
    appropriately.

    All usernames sent as TOC command arguments must be normalized (see
    TOC(7)). "$aim->norm_uname()" will do just this. Make sure to normalize
    usernames before passing them as arguments to "$aim->toc_format_msg()".

    "pw_roast" performs roasting as defined in TOC(7). It is not very
    exciting. I do not see why it is that you would ever need to do this, as
    "$aim->signon()" handles this for you (and the roasted password is
    stored in "$aim->{'roastedp'}"). However, if you want to play with it,
    there it is.

EXAMPLES
    See the file example.pl for an example of how to interact with this
    class.

FILES
    example.pl

        A sample client that demonstrates how this object could be used.

SEE ALSO
    See also TOC(7).

AUTHOR
    Copyright 2000-02 Riad Wahby <rsw@jfet.org> All rights reserved This
    program is free software. You may redistribute it and/or modify it under
    the same terms as Perl itself.

HISTORY
    0.01

        Initial Beta Release. (7/7/00)

    0.1

        First public (CPAN) release. (7/14/00)

    0.11

        Re-release under a different name with minor changes to the 
        documentation. (7/16/00)

    0.12

        Minor modification to fix a condition in which the server's
        connection closing could cause an infinite loop.

    1.0

        Changed the client agent string to TOC1.0 to fix a problem where
        connections were sometimes ignored.  Also changed the default signon
        port to 5198 and the login port to 1234.

    1.1

        Changed the client agent string again, this time to what seems
        like the "correct" format, which is
                PROGRAM:$Version info$
        Also added the ability to set a login timeout in case the SIGN_ON
        packet never comes.

    1.2

        Fixed a bug in toc_chat_invite that made it ignore some of its
        arguments.  This should fix various problems with using this
        subroutine.  Thanks to Mike Golvach for pointing this out.

    1.3

        Changed (defined @tci_buddies) to (@tci_buddies) in toc_chat_invite.
        Fixed a potential infinite loop in set_srv_buddies involving an
        off-by-one error in a for() test.  Thanks to Bruce Winter for
        pointing this out.

    1.4

        Changed the way that Net::AOLIM sends the login command string
        because AOL apparently changed their server software, breaking the
        previous implementation.  The new method requires that only the
        user agent string be in double quotes; all other fields should not
        be quoted.  Note that this does not affect the user interface at
        all---it's all handled internally.  Thanks to Bruce Winter, Fred
        Frey, Aryeh Goldsmith, and tik for help in tracking down and
        fixing this error.

        Also added additional checks to read_sflap_packet so that if the
        other end of the connection dies we don't go into an infinite
        loop.  Thanks to Chris Nelson for pointing this out.

    1.5

        Added a very simple t/use.t test script that just makes sure
        the module loads properly.

    1.6

        Patched around yet another undocumented "feature" of the TOC
        protocol---namely, in order to successfully sign on, you must have
        at least one buddy in your buddy list.  At sign-on, in the absence
        of a real buddy list, Net::AOLIM inserts the current user as a
        buddy in group "Me."  Don't bother removing this buddy, as it
        doesn't really exist---as soon as you add any real buddies, this
        one will go away.  Thanks to Galen Johnson and Jay Luker for
        emailing with the symptoms.

