The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

POE::Component::Client::POP3 - Impliment a POP3 client POE component

SYNOPSIS

    use POE::Component::Client::POP3;

    POE::Component::Client::POP3->spawn(
        Alias      => 'pop_client',
        Username   => 'bob',
        Password   => 'my password',
        AuthMethod => 'APOP',       # Other possible is PASS
        RemoteAddr => '192.168.1.101',
        RemotePort => 110,          # Default
        BindPort   => 1000,         # Default 0
        BindAddr   => INADDR_ANY,   # Default
        Events => [
            'connected',     # when we get connected
            'authenticated', # after authentication happens
            'error',         # write/read error happens
            'trans_error',   # The server returned an -ERR for a transaction
            'disconnected',  # we are disconnected
            'list',          # a list is retrieved
            'retr'           # a message is retrieved
        ]
    );

    # We are connected
    sub connected {
        my $msg = $_[ARG0];
        print "Connection message: $msg\n";
    }

    # We were disconnected
    sub disconnected {
        my $msg = $_[ARG0];
        print "Diconnected\n";
        print "Messgae: $msg\n" if defined $msg;
    }

    # We are authenticated
    sub authenticated {
        my $msg = $_[ARG0];
        print "Authenticated with message $msg\n";
    }

    # Catch errors
    sub error {
        my ( $state, $operation, $errnum, $errstr ) = @_[ARG0..ARG3];
        print "In state $state operation $operation".
              "error $errnum: $errstr\n";
        $poe_kernel->post( 'pop_client', 'quit' );
    }
    sub trans_error {
        my ( $state, $command, $input ) = @_[ARG0..ARG2];
        print "In state $state command $command we got input $input\n";
    }

    # Get a list of messages
    $poe_kernel->post( 
        'pop_client',  # The session we are posting to
        'list'         # Post to our list state
    );
    sub list {
        my $list = $_[ARG0]; # An hash ref

        for ( sort keys %$list ) {
            print "Message number $_ is $list->{$_} bytes\n";
        }
    }

    # Retrieve message 1
    $poe_kernel->post(
        'pop_client', # The session to post to
        'retr',       # retr state
        1,            # message 1
    );
    sub retr {
        # array ref of lines and message number
        my ( $msg, $msg_num ) = @_[ARG0, ARG1];

        print "Message number $msg_num is:\n", join( "\n", @$msg ), "\n";
    }

    # Retrieve the header and the first 10 lines of the
    # body of message 2
    $poe_kernel->post(
        'pop_client', # The session
        'top',        # The state
        2,            # message 2
        10            # header and 10 lines of the body
    );
    sub top {
        my ( $lines, $msg_num ) = @_[ARG0, ARG1];

        print "Message number $msg_num is:\n", join( "\n", @$msg ), "\n";
    }

    # Retrieve message 2 and write it to a file
    open my $handle, "/tmp/msg2" or die "Could not open /tmp/msg2; Reason: $!";
    $poe_kernel->post(
        'pop_client', # The session
        'retr',       # The state
        2,            # Message 2
        $handle       # The file handle to write it to
    );
    sub retr {
        my ( $handle, $msg_num ) = @_[ARG0, ARG1];

        print "Message $msg_num written to fileno ", fileno( $handle ), "\n";
        close $handle; @ Not really needed, it will go out of scope after this
    }

DESCRIPTION

POE::Component::Client::POP3 is a POE component for interacting with a POP3 server. This means it is an event driven way to communicate with a server that impliments Post Office Protocol Version 3 see rfc 1939 for details on the protocol.

CAVEATS

You should have a full understanding of POE, and atleast a familiarity with POP3 in order to grok this document.

Throughout this document POE::Component::Client::POP3 will be refered to as Client::POP3 for obvious reasons.

METHODS

Client::POP3 only has one public method. All other actions are performed by posting events back to the session that was created. This is similar to POE::Component::IRC and many other POE components

spawn

This method's arguments look like a hash but are really a list. You will call this method to get everything going, it is similar to most modules new() method but it does not return an object but creats a session for you to post events to.

The following is a list of the arguments it takes.

Alias

Name of the kernel alias Client::POP3 will make for it's session. You must supply this. This is what you will be posting events to.

Events

An array reference of the events you wish posted back to you when certain things happen. See "register" elsewhere in the document for a description of what the array reference should contain.

Username

This is the username to login as once we get connected. If you do not specify this no attempt to login will be made once we connect.

Password

The password to use for authentication. If not specified no attempt will be made to authenticate once we are connected. You will need to catch the connection event and do the authentication yourself by posting a login event with the proper username and password see "login" elsewhere in this document.

AuthMethod

This is the type of authentication we will attempt on the remote server. There are two type APOP and PASS. PASS method use the USER and PASS command to send the username and password in the clear. The APOP method used the APOP command to send the username and password. The password is md5 encoded with a string from the server before it is sent. The remote server must support APOP in order for this to work, see RFC1932 page 15 for further description of how this works. This method requires Digest::MD5 be installed.

RemoteAddr

This is the hostname or ip address of the remote POP3 server we are connecting to, it is required.

RemotePort

This is the port on the remote machine we are connecting to. It will default to 110 if not defined.

BindAddr

This supplies the address where the socket will be bound to. BindAddr may contain a string or a packed Internet address. The string form should hold either an ip address or a hostname. This defaults to INADDR_ANY.

BindPort

This contains a port on the BindAddr to bind to. It defaults to zero. BindPort may be either a port number or a named service. See perldoc -f bind for more information.

INPUT

Client::POP3 receives events from the session or sessions that want it to perform actions. These events are posted to the Alias you specified when you called spawn(). For example:

    $poe_kernel->post( 'alias_i_set', 'list' );

Assuming you set Alias to 'alias_i_set', this will tell Client::POP3 to send a LIST command to the server, when the data is received Client::POP3 will then send you a 'list' event or whatever you aliased the 'list' event to.

This is a list of all the events you should post to the Client::POP3 session.

register

In order to tell Client::POP3 what events you would like and would not like you need to regester them or unregister them. The event register takes a list of arguments. If an argument is a hash, the key will be the event Client::POP3 has to post and the value will be the event you would like posted in to your session. If the argument is a scalar it will register that event to post to your session by it's own name. For example:

    $kernel->post(
        'pop_client',
        'register'
        'list',
        { error => 'oops' }
    );

Will tell Client::POP3 to post 'list' to you when that event happens and to post 'oops' to you when the error event happens. The order of the arguments does not matter.

unregister

To unregister an event (Client::POP3 stops posting it to you) simply post an event unregister with the list of event you no longer care about and they will not be sent to you any longer. For example:

    $poe_kernel->post( 'pop_client', 'unregister', 'error', 'list' );

Would unregister the events 'error' and 'list'.

login

This is the event that causes Client::POP3 to attempt to login to the remote server. This event should only be posted after the connection is established. Arguments to this event are username, password, auth type. In that order. Here is an example

    $poe_kernel->post(
        'pop_client',
        'login',
        "bob",
        "bob's password",
        "PASS"
    );

This will tell Client::POP3 to login as USER 'bob' with PASS 'bob's password' using the PASS method. The third argument is not manditory and if omited will default to PASS.

You will generally not need to send this event unless an error happens during login and you wish to resubmit a different username and password to the server, as this event is fired automaticly when you specify the Username and Password parameters to spawn().

stat

Send a STAT command to the server. This gets the size and number of messages on the remote server. A 'stat' event is posted back to you when the information is retrieved. This event takes no arguments.

    $poe_kernel->post( 'pop_client', 'stat' );
list

Send a LIST command to the server. This event can take either one or no arguments. In the no argument for a list of all the messages on the remote server is posted back to you, with there sizes. If a single argument is given it is expected to be the number of the message you wish to list, in this case just that messages size and number is posted back to you.

    $poe_kernel->post( 'pop_client', 'list' );
    -or-
    $poe_kernel->post( 'pop_client', 'list', $message_number );
uidl

This event is very similar to 'list' in what it does and takes. You can post this event with no arguments to get a list of all the messages and there uidl (unique id) or you can send an argument that is expected to be the message number you with the uidl for.

    $poe_kernel->post( 'pop_client', 'uidl' );
    -or-
    $poe_kernel->post( 'pop_client', 'uidl', $msg_number );
retr

This events is to get an email off the remote server. The arguments are the message number to get and an optional filehandle to write the message to. If no filehandle is given, when the message is retrieved, the 'retr' event will be posted to you with an array reference of all the lines in the email. If given with a filehandle, after the message is written to the handle, the 'retr' event posted to you will contain the filehandle that it was written to instead of the lines in an array.

    $poe_kernel->post( 'pop_client', 'retr', $msg_number );
    -or-
    $poe_kernel->post( 'pop_client', 'retr', $msg_number, \*FH );
top

This event acts the same as the 'retr' however there is one additional argument, the number of lines from the body to retrieve. If the number of lines if not defined the entire body is retrieved.

    $poe_kernel->post( 'pop_client', 'top', $msg_number, $num_lines );
    -or-
    $poe_kernel->post( 'pop_client', 'top', $msg_number, $num_lines, \*FH );
dele

This is how you delete messages from the remote server. The messages are not actually deleted until you post a 'quit' event. The only argument to this event is the number message to delete. You would get this message number from a 'list' event.

    $poe_kernel->post( 'pop_client', 'dele', $msg_number );
noop

This event tells Client::POP3 to send a NOOP command to the server, this is good for servers that have a timeout on connection in that it usually resets the timeout. This event takes no arguments.

    $poe_kernel->post( 'pop_client', 'noop' );
rset

This event tells Client::POP3 to send a RSET command to the server. This tells the server to reset all delete flags. This event takes no arguments.

    $poe_kernel->post( 'pop_client', 'rset' );
quit

This event causes Client::POP3 to call quit on the remote server and to disconnect. This event takes no arguments.

    $poe_kernel->post( 'pop_client', 'quit' );

OUTPUT

These are events that you may request to be posted to your session. You do this by specifing them when you call spawn() with the 'Events' argument or by posting the event 'register'.

trans_error

This event is posted when the server send us an error reply to a command. e.i. -ERR Command not implimented. The -ERR part of the message is stripped off before it is sent to you. The arguments to the event handler are state, command, and server input. State will be one of auth or trans. auth means we were not authenticated yet and trans means we were.

    sub trans_error {
        my ( $state, $command, $server_input ) = @_[ARG0..ARG2];
        ...
    }
error

This event is fired when Wheel::ReadWrite sends us an error, usually either a read or write error. Four arguments are passed to this event handler. The first one is the state we were in, 'connect', 'auth' or 'trans'. 'auth' meaning were are in the authentication state, 'trans' meaning we were in the transaction state and 'connect' meaning we have yet to connect. The second argument is the operation that failed, probably 'read' or 'write', the third argument is the error number, this corresponds to Errno, see Errno for details on what this number means. The last argument is the error string, e.g. "Socket is not connected".

    sub error {
        my ( $state, $operation, $errnum, $errstr ) = @_[ARG0..ARG3];
        ...
    }
connected

This event is fired after the socket has been connected but before authentication. If you didn't specify the 'Username' and 'Password' parameters you would want to post a 'login' event to Clinet::POP3 now.

    sub connected {
        my $server_input = $_[ARG0];
        ...
    }
disconnected

This event is fired when the socket is disconnected. You will not get this event if the socket was diconnected with an error, you will get the 'error' event instead. You should also expect this event after you post a 'quit' event. One argument is posted to this event's handler, and that is what the server said, if the server closes the connection without saying goodbye :( the argument will be undefined.

    sub disconnected {
        my $server_input = defined( $_[ARG0] ) ? $_[ARG0] : 'None';
        ...
    }
authenticated

This event is fired after athentication succeeds. You will want to catch this event in order to start performing operations like listing messages and whatnot. No arguments are passed to this events handler.

    sub authenticated {
        ...
    }
stat

This event is fired when we receive the return of a stat request done on the server. The arguments to this events handler is the number of messages and the total size of all messages.

    sub stat {
        my ( $num_msgs, $size_msgs ) = @_[ARG0, ARG1];
        ...
    }
list

Fired when we receive the output from a list command. The only argument is a hash reference, the keys are the message numbers and the values are the sizes of the messages.

    sub list {
        my $list_href = $_[ARG0];
        ...
    }
uidl

Fired when we receive the output from a uidl command. The only argument is a hahs reference, the keys are the message numbers and the values are the unique uidl's.

    sub uidl {
        my $uidl_href = $_[ARG0];
        ...
    }
retr

This event is fired when we finish receiving a an email requested by a retr command. If you requested the message be written to a filehandle then the first argument is the filehandle else the first argument is an array reference of the lines of the message with no EOL character on them. The second argument is the message number retrieved.

    sub retr {
        my ( $msg_aref, $msg_num ) = @_[ARG0, ARG1];
        ...
    }
    -or-
    sub retr {
        my ( $msg_fh, $msg_num ) = @_[ARG0, ARG1];
        ...
    }
top

This event is fired when we have finished getting the output from a top command. If you requesed to have the output written to a filehandle, the first argument to this event's handler is the filehandle it was written to else the first argument is an array of lines without an EOL. The second argument if the message number retrieved.

    sub top {
        my ( $msg_aref, $msg_num ) = @_[ARG0, ARG1];
        ...
    }
    -or-
    sub top {
        my ( $msg_fh, $msg_num ) = @_[ARG0, ARG1];
        ...
    }
dele

Fired when the responce to a dele command is returned. The event's handler receives two arguments. The first is the response from the server without the +OK at the beginning. The second is the message number marked for deletion.

    sub dele {
        my ( $server_input, $msg_num ) = @_[ARG0, ARG1];
        ...
    }
noop

Fired when the responce from a noop command is returned. The only argument is the responce from the server without the +OK at the start of it.

    sub noop {
        my $server_input = $_[ARG0];
        ...
    }
rset

Fired when the responce from a rset command is returned. The only argument is the responce from the server without the +OK at the start of it.

    sub rset {
        my $server_input = $_[ARG0];
        ...
    }
quit

Fired when the responce from a quit command is returned. The only argument is the responce from the server without the +OK at the start of it. NOTE: You may never get this event when you quit, many servers do not send a responce to a quit command.

    sub quit {
        my $server_input = $_[ARG0];
        ...
    }

SEE ALSO

POE, perl, RFC1939, RFC1957, RFC1725

BUGS

Plenty I'm sure.

AUTHORS & COPYRIGHTS

Except where otherwise noted, POE::Component::Client::POP3 is Copyright 2002-2003 Scott Beck <scott@gossamer-threads.com>. All rights reserved. POE::Component::Client::POP3 is free software; you may redistribute it and/or modify it under the same terms as Perl itself.