NAME

    POE::Component::Server::POP3 - A POE framework for authoring POP3
    servers

VERSION

    version 0.12

SYNOPSIS

      # A simple POP3 Server that demonstrates functionality
      use strict;
      use POE;
      use POE::Component::Server::POP3
    
      POE::Session->create(
            package_states => [
              'main' => [qw(
                            _start
                            pop3d_registered
                            pop3d_connection
                            pop3d_disconnected
                            pop3d_cmd_quit
                            pop3d_cmd_user
                            pop3d_cmd_pass
                            pop3d_cmd_stat
                            pop3d_cmd_list
                            pop3d_cmd_noop
              )],
            ],
      );
    
      $poe_kernel->run();
      exit 0;
    
      sub _start {
        $_[HEAP]->{pop3d} = POE::Component::Server::POP3->spawn(
            hostname => 'pop.foobar.com',
        );
        return;
      }
    
      sub pop3d_registered {
        # Successfully started pop3d
        return;
      }
    
      sub pop3d_connection {
        my ($heap,$id) = @_[HEAP,ARG0];
        $heap->{clients}->{ $id } = { auth => 0 };
        return;
      }
    
      sub pop3d_disconnected {
        my ($heap,$id) = @_[HEAP,ARG0];
        delete $heap->{clients}->{ $id };
        return;
      }
    
      sub pop3d_cmd_quit {
        my ($heap,$id) = @_[HEAP,ARG0];
        unless ( $heap->{clients}->{ $id }->{auth} ) {
            $heap->{pop3d}->send_to_client( $id, '+OK POP3 server signing off' );
            return;
        }
        # Process mailbox in some way
        $heap->{pop3d}->send_to_client( $id, '+OK POP3 server signing off' );
        return;
      }
    
      sub pop3d_cmd_user {
        my ($heap,$id) = @_[HEAP,ARG0];
        my $user = ( split /\s+/, $_[ARG1] )[0];
        unless ( $user ) {
            $heap->{pop3d}->send_to_client( $id, '-ERR Missing username argument' );
            return;
        }
        $heap->{clients}->{ $id }->{user} = $user;
        $heap->{pop3d}->send_to_client( $id, '+OK User name accepted, password please' );
        return;
      }
    
      sub pop3d_cmd_pass {
        my ($heap,$id) = @_[HEAP,ARG0];
        my $pass = ( split /\s+/, $_[ARG1] )[0];
        unless ( $pass ) {
            $heap->{pop3d}->send_to_client( $id, '-ERR Missing password argument' );
            return;
        }
        $heap->{clients}->{ $id }->{pass} = $pass;
        # Check the password
        $heap->{clients}->{ $id }->{auth} = 1;
        $heap->{pop3d}->send_to_client( $id, '+OK Mailbox open, 0 messages' );
        return;
      }
    
      sub pop3d_cmd_stat {
        my ($heap,$id) = @_[HEAP,ARG0];
        unless ( $heap->{clients}->{ $id }->{auth} ) {
            $heap->{pop3d}->send_to_client( $id, '-ERR Unknown AUTHORIZATION state command' );
            return;
        }
        $heap->{pop3d}->send_to_client( $id, '+OK 0 0' );
        return;
      }
    
      sub pop3d_cmd_noop {
        my ($heap,$id) = @_[HEAP,ARG0];
        unless ( $heap->{clients}->{ $id }->{auth} ) {
            $heap->{pop3d}->send_to_client( $id, '-ERR Unknown AUTHORIZATION state command' );
            return;
        }
        $heap->{pop3d}->send_to_client( $id, '+OK No-op to you too!' );
        return;
      }
    
      sub pop3d_cmd_list {
        my ($heap,$id) = @_[HEAP,ARG0];
        unless ( $heap->{clients}->{ $id }->{auth} ) {
            $heap->{pop3d}->send_to_client( $id, '-ERR Unknown AUTHORIZATION state command' );
            return;
        }
        $heap->{pop3d}->send_to_client( $id, '+OK Mailbox scan listing follows' );
        $heap->{pop3d}->send_to_client( $id, '.' );
        return;
      }

DESCRIPTION

    POE::Component::Server::POP3 is a POE component that provides a
    framework for authoring POP3 http://www.faqs.org/rfcs/rfc1939.html
    servers with POE.

    It creates a listening TCP socket ( by default on port 110 ) and
    accepts connections from multiple clients. Each connecting client is
    assigned a unique ID. Input from clients generates events that other
    POE components and sessions may register to receive. The POP3 poco also
    handles sending output to applicable clients.

    One may either interface with the component via the POE API or via
    POE::Component::Pluggable plugins.

CONSTRUCTOR

    spawn

      Takes a number of optional arguments:

        'alias', set an alias on the component;
        'address', bind the listening socket to a particular address;
        'port', listen on a particular port, default is 110;
        'options', a hashref of POE::Session options;
        'hostname', the name that the server will identify as;
        'version', change the version string reported in initial client connections;
        'handle_connects', set this to a false value to stop the component sending
              initial connection responses to connecting clients;

      Returns a POE::Component::Server::POP3 object.

METHODS

    session_id

      Returns the POE::Session ID of the component.

    shutdown

      Terminates the component. Shuts down the listener and disconnects
      connected clients.

    send_event

      Sends an event through the component's event handling system.

    send_to_client

      Send some output to a connected client. First parameter must be a
      valid client id. Second parameter is a string of text to send.

    disconnect

      Places a client connection in pending disconnect state. Requires a
      valid client ID as a parameter. Set this, then send an applicable
      message to the client using send_to_client() and the client
      connection will be terminated.

    getsockname

      Access to the POE::Wheel::SocketFactory method of the underlying
      listening socket.

INPUT EVENTS

    These are events that the component will accept:

    register

      Takes N arguments: a list of event names that your session wants to
      listen for, minus the 'pop3d_' prefix, ( this is similar to
      POE::Component::IRC ).

      Registering for all will cause it to send all POP3D-related events to
      you; this is the easiest way to handle it.

    unregister

      Takes N arguments: a list of event names which you don't want to
      receive. If you've previously done a 'register' for a particular
      event which you no longer care about, this event will tell the POP3D
      to stop sending them to you. (If you haven't, it just ignores you. No
      big deal).

    shutdown

      Terminates the component. Shuts down the listener and disconnects
      connected clients.

    send_event

      Sends an event through the component's event handling system.

    send_to_client

      Send some output to a connected client. First parameter must be a
      valid client ID. Second parameter is a string of text to send.

    disconnect

      Places a client connection in pending disconnect state. Requires a
      valid client ID as a parameter. Set this, then send an applicable
      message to the client using send_to_client() and the client
      connection will be terminated.

OUTPUT EVENTS

    The component sends the following events to registered sessions:

    pop3d_registered

      This event is sent to a registering session. ARG0 is the
      POE::Component::Server::POP3 object.

    pop3d_listener_failed

      Generated if the component cannot either start a listener or there is
      a problem accepting client connections. ARG0 contains the name of the
      operation that failed. ARG1 and ARG2 hold numeric and string values
      for $!, respectively.

    pop3d_connection

      Generated whenever a client connects to the component. ARG0 is the
      client ID, ARG1 is the client's IP address, ARG2 is the client's TCP
      port. ARG3 is our IP address and ARG4 is our socket port.

      If 'handle_connects' is true ( which is the default ), the component
      will automatically send an initial connection response to the client.

    pop3d_disconnected

      Generated whenever a client disconnects. ARG0 is the client ID.

    pop3d_cmd_*

      Generated for each POP3 command that a connected client sends to us.
      ARG0 is the client ID. ARG1 .. ARGn are any parameters that are sent
      with the command. Check the RFC http://www.faqs.org/rfcs/rfc1939.html
      for details.

PLUGINS

    POE::Component::Server::POP3 utilises POE::Component::Pluggable to
    enable a POE::Component::IRC type plugin system.

 PLUGIN HANDLER TYPES

    There are two types of handlers that can registered for by plugins,
    these are

    POP3D

      These are the 'pop3d_' prefixed events that are generated. In a
      handler arguments are passed as scalar refs so that you may mangle
      the values if required.

    POP3C

      These are generated whenever a response is sent to a client. Again,
      any arguments passed are scalar refs for manglement. There is really
      on one type of this handler generated 'POP3C_response'

 PLUGIN EXIT CODES

    Plugin handlers should return a particular value depending on what
    action they wish to happen to the event. These values are available as
    constants which you can use with the following line:

      use POE::Component::Server::POP3::Constants qw(:ALL);

    The return values have the following significance:

    POP3D_EAT_NONE

      This means the event will continue to be processed by remaining
      plugins and finally, sent to interested sessions that registered for
      it.

    POP3D_EAT_CLIENT

      This means the event will continue to be processed by remaining
      plugins but it will not be sent to any sessions that registered for
      it. This means nothing will be sent out on the wire if it was an
      POP3C event, beware!

    POP3D_EAT_PLUGIN

      This means the event will not be processed by remaining plugins, it
      will go straight to interested sessions.

    POP3D_EAT_ALL

      This means the event will be completely discarded, no plugin or
      session will see it. This means nothing will be sent out on the wire
      if it was an POP3C event, beware!

 PLUGIN METHODS

    The following methods are available:

    pipeline

      Returns the POE::Component::Pluggable::Pipeline object.

    plugin_add

      Accepts two arguments:

        The alias for the plugin
        The actual plugin object

      The alias is there for the user to refer to it, as it is possible to
      have multiple plugins of the same kind active in one
      POE::Component::Server::POP3 object.

      This method goes through the pipeline's push() method.

       This method will call $plugin->plugin_register( $pop3d )

      Returns the number of plugins now in the pipeline if plugin was
      initialized, undef if not.

    plugin_del

      Accepts one argument:

        The alias for the plugin or the plugin object itself

      This method goes through the pipeline's remove() method.

      This method will call $plugin->plugin_unregister( $pop3d )

      Returns the plugin object if the plugin was removed, undef if not.

    plugin_get

      Accepts one argument:

        The alias for the plugin

      This method goes through the pipeline's get() method.

      Returns the plugin object if it was found, undef if not.

    plugin_list

      Has no arguments.

      Returns a hashref of plugin objects, keyed on alias, or an empty list
      if there are no plugins loaded.

    plugin_order

      Has no arguments.

      Returns an arrayref of plugin objects, in the order which they are
      encountered in the pipeline.

    plugin_register

      Accepts the following arguments:

        The plugin object
        The type of the hook, POP3D or POP3C
        The event name(s) to watch

      The event names can be as many as possible, or an arrayref. They
      correspond to the prefixed events and naturally, arbitrary events
      too.

      You do not need to supply events with the prefix in front of them,
      just the names.

      It is possible to register for all events by specifying 'all' as an
      event.

      Returns 1 if everything checked out fine, undef if something's
      seriously wrong

    plugin_unregister

      Accepts the following arguments:

        The plugin object
        The type of the hook, pop3D or POP3C
        The event name(s) to unwatch

      The event names can be as many as possible, or an arrayref. They
      correspond to the prefixed events and naturally, arbitrary events
      too.

      You do not need to supply events with the prefix in front of them,
      just the names.

      It is possible to register for all events by specifying 'all' as an
      event.

      Returns 1 if all the event name(s) was unregistered, undef if some
      was not found.

 PLUGIN TEMPLATE

    The basic anatomy of a plugin is:

            package Plugin;
    
            # Import the constants, of course you could provide your own 
            # constants as long as they map correctly.
            use POE::Component::Server::POP3::Constants qw( :ALL );
    
            # Our constructor
            sub new {
                    ...
            }
    
            # Required entry point for plugins
            sub plugin_register {
                    my( $self, $pop3d ) = @_;
    
                    # Register events we are interested in
                    $pop3d->plugin_register( $self, 'POP3D', qw(all) );
    
                    # Return success
                    return 1;
            }
    
            # Required exit point for pluggable
            sub plugin_unregister {
                    my( $self, $pop3d ) = @_;
    
                    # Pluggable will automatically unregister events for the plugin
    
                    # Do some cleanup...
    
                    # Return success
                    return 1;
            }
    
            sub _default {
                    my( $self, $pop3d, $event ) = splice @_, 0, 3;
    
                    print "Default called for $event\n";
    
                    # Return an exit code
                    return POP3D_EAT_NONE;
            }

SEE ALSO

    POE::Component::Pluggable

    RFC 1939 http://www.faqs.org/rfcs/rfc1939.html

AUTHOR

    Chris Williams <chris@bingosnet.co.uk>

COPYRIGHT AND LICENSE

    This software is copyright (c) 2017 by Chris Williams.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.