Skip Headers
Oracle® Mail Application Developer's Guide
10g Release 1 (10.1.1)

Part Number B15789-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

4 Mail Server Plug-In Framework

The Oracle Collaboration Suite Mail server plug-in interface provides a framework to pass mail and messaging information between existing Oracle Mail protocol servers and third-party vendor and partner products. This interface can be used to extend the functionality of mail servers in many ways - for example, to scan the mail system for viruses, provide efficient workflow integration, or track and archive mail messages that have entered or left the system.

Introduction to the Mail Server Framework Plug-In API

The Mail Server Framework allows two types of plug-ins. The first takes the form of a separate executable, written in any language, and spawned from the SMTP processes. The second is a shared library written in C and linked into the SMTP processes. Libraries are written and compiled like any non-Oracle Mail Server library, without added precompilation or preprocessing. However, plug-in libraries must be linked as shared libraries. The library plug-ins will be loaded into the Mail server address space during server startup. Configuration of both types of plug-ins is done through policy pages. For more information on configuring plug-ins, see Chapter 8, "Oracle Mail Policies"" of Oracle Mail Administrator's Guide.

If the plug-in is a separate application or executable, the appropriate mail process will spawn the executable for each mail message. The mail message is passed to the application through standard input. If the custom executable is called from a mail process that uses envelope information, then the envelope information will be passed on the command line as well.

The Mail Server processes can call the plug-ins at specific event control points, of which there are two types. There are high-level event control points, which specify when plug-ins are called, and low-level event control points, which define the information passed to the plug-in. A system administrator will set the high-level event control points through the administration pages. Low-level control points apply only to C plug-ins (shared libraries) and the plug-in specifies these control points as a list of services supported by the filter interface.

When to Call the Plug-in

Mail processes that route or send mail messages will eventually pass through high-level event control points. There are three such control points. The first point is called Incoming, which is reached as the message enters the mail process that routes or sends a message, regardless of the sender or recipient of the message. Note that the scanner plug-in interface is not called until after the message passes through the protocol server's mail relay control logic. That is, if the SMTP servers are not open relays, then all messages that pass the relay constraints will go through this event control point.

After the protocol server reviews the recipient list of the mail message, all messages that are destined for one or more recipients in one of the local domains will pass through the Local event. Afterwards, messages that are destined for one or more recipients in a mail domain that is not local will pass through the Outgoing event. Mail messages destined for recipients both a local domain and an external domain will pass through both Outgoing and Local event control points.

  1. INCOMING - A plug-in configured to be called on the routing of all messages will be called for every message when a connection is made to the mail protocol service or when a message is submitted into a mail store.

  2. OUTGOING - A plug-in configured to be called for outgoing will be called just before a connect request is made to the next message transfer agent.

  3. LOCAL - A plug-in configured to be called for local will be called just before local delivery to the inbox or news store.

Each high-level event control point can call an array of one or more custom plug-ins. The order by which each plug-in is called can be set in the administration pages. If both types of plug-ins are configured for a Mail server, the framework will call C plug-ins in the specified order before external process plug-ins. Messages and connections will pass through the Incoming high-level event control point before passing through either the Outgoing or Local control points.

C Plug-In Service Support

Information passed to a plug-in depends upon the services supported by the plug-in. The information is passed at low-level control points, which include Connect, Reset, Envelope, Message, and Authentication.

Table 4-1 Services Supported by Server Type

Server Type CONNECT AUTH ENVELOPE MESSAGE RESET

SMTP_IN

MANDATORY

No

Yes

Yes

MANDATORY

SMPT_OUT

MANDATORY

No

Yes

Yes

MANDATORY

NNTP_IN

MANDATORY

Yes

Yes

Yes

MANDATORY

LS

MANDATORY

No

No

Yes

MANDATORY

VS

MANDATORY

No

No

Yes

MANDATORY


The above table shows the low-level services each of the six mail protocol server types are able to call. A plug-in must write a CONNECT and a RESET function. All protocol server types always call these two functions. Protocol servers optionally support AUTH, ENVELOPE, and MESSAGE functions. In the case of AUTH, only the NNTP_IN process supports this low-level event control point.

Calling the Plug-In From the Mail Protocol Server

All custom plug-ins must be placed in a specific directory, or the plug-in shared library must be in the LD_LIBRARY_PATH environment variable. Each middle-tier Oracle home has the directory structure ./oes/lib below the Oracle home where the plug-ins should be located. If the shared library is not in this directory, then the LD_LIBRARY_PATH environment variable must include the directory where the library is located. The name (or complete path, if an executable) of the plug-in must be entered in the filter maintenance page when managing policies through the administration tools.

Furthermore, if the plug-in is a shared library, the plug-in must support a list of mandatory functions. The functions for the initialization, registration, and close actions are mandatory and must have specific names so that the mail protocol servers know how to call them. Within the initialization function, a plug-in will tell the protocol server which low-level event control points the plug-in can process. The registration function provides function pointers to the plug-in to request services of the mail protocol server.

Header File Inclusion for C Plug-ins

All custom plug-ins must include the C interface definition located in the esefif.h header file. This header file contains:

External Filter Process Plug-In

The Mail server framework provides a way to integrate external processes into a mail server. The Mail server invokes a configured filter at each of a series of high-level control points and communicates with the spawned process using standard input and output. The external filter executable must have its permissions set to Execute. The Mail server will throw errors in its log if it fails to spawn the filter process.

Communication from Mail Server to External Filter Process

Both the message body and envelope are passed when the filter process is spawned by the Mail server. The call to the external process will pass the envelope information, as well as other information (such as message size) by command-line arguments in the syntax described below. The filter process reads the envelope information using argv[]. The message body is passed to the standard input (stdin) of the external process; the filter process must read its standard input until EOF (end of file) occurs, indicating the end of the passed message. The Mail server will return errors if the filter process exits or aborts before the complete message body is sent by the Mail server.

Communication from External Filter Process to Mail Server

The external process can apply its own filtering on the envelope and the received message body. The process must return a status code (success, failure or modify) to the Mail server on the standard output (stdout). If a success status is received, the Mail server proceeds with running the remaining filters (if any) or with delivery processing of the mail message. If a failure status is received from the external filter, the message will be rejected by the Mail server and will not be delivered. The external filter can also pass a modified mail message back to the server, which is then delivered to the recipients. If the external process aborts or exits during processing of a mail message, the Mail server will assume a temporary processing error. In this case, the server will re-queue the message and retry according to the Mail server's retry mechanism.

Command-Line Arguments

The call to the external process has the following syntax:

filter_process host=host mailfrom=mailfrom rcptto=rcptto msgsize=msg_size

where

  • filter_process is the path of external filter executable as given in the administration pages,

  • host is the host name of mail client,

  • mailfrom is the address sent by the client during the Mail server protocol exchange,

  • rcptto is the list of recipients from the Mail server protocol exchange. This is a list separated by a comma and is enclosed in brackets and,

  • msg_size is the size of the mail message.

The external filter process should rely on the keywords in the arguments rather than the contents of the argv array. For example, host information will not necessarily be passed in argv[1].

Format of Output from External Filter Process

After the filter process has finished processing the mail, it should return the status and the changed message (if any) back to the server. To do this, the process must write the following information to its standard output (stdout):

status_code [version_definition]
repaired_message

where

  • possible value for status_code are

    • 0 - The message is clean and is to be sent to the recipient

    • 1 - The message is not clean and is to be rejected

    • 2 - The message was not clean but was repaired, or the message was modified for Mail policy reasons. The changed message will be sent to recipients.

  • version_definition can be returned optionally by the filter process and is stored with the message. This can be used to store version information, such as a virus definition database identifier. Because it is stored with the message, it can be used later in the virus scrubber process to selectively re-scan messages.

  • repaired_message is the modified message that should be sent to recipients.

C Plug-in Filter Process Flow

Initialization and Registration

The plug-in tells the protocol server which services it supports during the initialization phase so that the protocol server or virus scrubber knows how to call the plug-in. Through a series of callback registrations during the initialization phase, the plug-in learns how to communicate back to the server. When a mail protocol server first loads, the server calls the plug-in's esefifInit() function, and then calls the esefifRegister() function repeatedly, once for each framework callback service supported by MTA. Each time the server calls esefifRegister(), it passes the plug-in a function pointer to one of the services it could provide. For example, it could tell the plug-in how to communicate with the framework and log a message in the mail protocol server log file.

The mail protocol servers are multi-threaded, and each thread can handle a connection. During the connection, the thread will call the plug-in at each supported low-level event control point.

Processing Low-Level Control Points

The five low-level event control points are passed through on a per-connection basis. The exception is the virus scrubber process, which runs against a mail store. For example, assume a plug-in written for the Oracle Message Transfer Agent (SMTP_IN process in this case) notifies the Oracle protocol server that it supports Connect, Message, and Reset servers (assume it does not support Envelope). Now suppose a remote MTA sends three messages over a single connection to the Oracle Message Transfer Agent. The protocol server would call esefifConnect() once after the remote MTA has opened a connection. Then it would call esefifMessage() three times; once after each message is received. Finally esefifReset() would be called when the connection is dropped or closed. If the plug-in published supported "ENVELOPE" as well, then esefifEnvelope() and esefifMessage() would be called three times each.

esefifReset() gets called at the end of the connection or if the client (or remote MTA) requests a temporary reset for the currently processed message. The plug-in can determine which type of reset is being called (i.e. the difference between End of Message/Connection and temporary message reset). The plug-in is responsible for any message level and connection-level cleanup of structures.

The plug-in framework allows a single plug-in (shared library) to be called by multiple protocol server types. The above plug-in could also apply to the virus scrubber. The virus scrubber would call esefifConnect(), then esefifMessage() and finally esefifReset() for each message that met the filter requirements.

Shutting Down

When a mail protocol server shuts down, the server calls the plug-in's esefifClose() function. The plug-in can then release resources allocated during esefifInit() as well as perform any other necessary cleanup.

Transferring Information Between a Plug-In and Mail Protocol Server

Information is passed between a protocol server and a plug-in through function pointers, which are registered with the plug-in when the protocol server starts. Each protocol server type will publish callback service functions to the plug-in, which can then call these functions as needed.

  • Framework Send function - This function asks the framework to send the message to the plug-in. Since an email message can be quite large, calling this function causes the Oracle protocol server to, in turn, call the plug-in esefifSend() function in a loop. Each time esefifSend() is called, the protocol server sends a chunk of the message until the complete message is accepted.

  • Framework Receive function - This function asks the framework to receive the message from the plug-in. This is called if the plug-in needs to modify the message before handing it back to the protocol server. For example, a virus scanning plug-in might "clean" a message and return it, or a disclaimer-adding plug-in might append a disclaimer and pass the message on. As an email message can be quite large, calling this function causes the Oracle protocol server to, in turn, call the plug-in esefifRecv() function in a loop. Each time esefifRecv() is called, the plug-in sends a chunk of the message until the complete message is accepted.

  • Framework Get Envelope function - This function asks the framework to send the envelope information associated with this message. This information includes recipient list, sender, host, and authenticated user. When called at the Incoming event control point, the function returns a complete list of unresolved recipients and if available, a complete list of resolved recipients.. When called at Relay or Local control points, the recipient list is resolved but only contains relay or local domain recipients.

  • Framework Get Header Information function - This function asks the framework to send the header information associated with this message. This will return the top-level header of the message in the format it was received from the client (or other MTA).

  • Framework Get Message Size function - This function asks the framework to send the size of the message, in bytes.

  • Framework Get Message Identifier function - Each mail protocol server has a default mail store where it performs certain tasks. This function asks the framework to send the mail store message identifier. Note that a single message stored in two different mail stores will have two different message identifiers.

  • Framework Allocate Memory function - A plug-in can request the protocol server calling it to allocate memory on its behalf. Doing so uses the heap of the protocol server as opposed to the plug-in, which saves operating system calls.

  • Framework Free Memory function - All memory explicitly requested by a plug-in from the framework must be freed with the framework's free memory function call.

  • Framework Set Version definition - The Oracle mail store schema includes a history table (es_scan_history) of the messages that passed through the plug-in interface. The table consists of the mail store message identifier, scanner (plug-in) name, a definition, and a date stamp when the message passed through the plug-in. Each time a message passes through a plug-in, the plug-in can tell the protocol server to insert a record into the es_scan_history table.

  • Framework Add a Recipient function - This function adds a "rcpt to:" entry to the message envelope.

  • Framework Delete a Recipient function - This function removes a "rcpt to:" entry from the message envelope.

  • Framework Log function - This function logs a message from a plug-in.

  • Framework Get Policy Identifier - This function returns the archive policy ID (if any) of the calling plug-in. This function applies only to plug-ins used for archiving purposes.

Copying a Message Between the Server and Plug-in

The esefifMessage() is called by the protocol server when that protocol server has a message it wants the plug-in to process. Once the plug-in receives this notification, it would then call a framework function (for example, "Send Message" or "Get Message Size") within its esefifMessage() function.

Upon receiving a "Send Message" request from the plug-in, the protocol server will call the function esefifSend() in a loop, each time passing a chunk of the message, until the whole message has been passed. The plugin must collect these "chunks" and rebuild the message inside their esefifSend() function.

To return a modified message back to the protocol server, the plug-in would call the "Receive Message" framework function, and the protocol server would in turn call the plug-in's esefifRecv() function in a loop until the protocol server receives the complete modified message.

C Plug-In Functions

Plug-ins are written in C. The plug-in must be built as a shared library. A plug-in should contain the following functions:

Table 4-2 Mandatory Functions for Implementation by C Plug-Ins

Function Mandatory? Description

esefifInit()

Yes

The initialization function for the custom library. At a minimum, a global set of contexts must be initialized to pass between the Oracle mail protocol servers and the custom library.

esefifClose()

Yes

Performs any necessary tasks prior to shutdown. For example, freeing resources allocated in esefifInit().

esefifRegister()

Yes

Registers, in the context of the plug-in, all the mail protocol server routines the framework provides.

esefifConnect()

Yes

SERVICE: Processing at the end of the connect request.

esefifEnvelope()

No

SERVICE: Called when envelope information is received.

esefifMessage()

No

This function is called by the protocol server when that protocol server has a message it wants the plug-in to process.

esefifReset()

Yes

Processing at the end of each Message

esefifSend()

No

Receives the message sent from the mail protocol server to the plug-in.

esefifRecv()

No

Sends a modified (cleaned, appended, etc.) message received by the mail protocol server from the plug-in.


Return Codes

All plug-in functions must be written to return one of the following four return values. Note: some functions do not modify or reject mail messages and hence do not return those codes.

Table 4-3 Return Codes for C Plug-In Functions

Code Description

ESEFIF_SUCCESS

Success.

ESEFIF_REJECT

Failure. A plug-in service function should return this code to the mail protocol server if it does not want the protocol server to allow the message to be sent or the connection to continue.

ESEFIF_MODIFIED

Message Modified. The return code a plug-in service function returns in order to tell the mail protocol server that it needs to modify or clean the message before the message should be allowed to continue.

ESEFIF_ERROR

Error.



esefifInit()

int esefifInit(void **ifgctx,
               void *efgctx,
               void **services,
               char *scanflags,
               char *sysflags);

Purpose

Parameters

ifgctx (OUT)

This is pointer to the global context of the plug-in. This context gets passed back to the plug-in by the Oracle mail protocol server every time a protocol server calls the plug-in and for every message.

efgctx (IN)

This is pointer to the global context for the framework. This pointer must be passed in each framework function call.

services (OUT)

This is a text string specifying the services supported by the plug-in and the name the function the protocol server must call to process the service. The syntax of the string is a single character ("E" or "F") followed by a colon followed by a list of services or service function names separated by commas. A string starting with "E:" is a variable number of elements listing the service names that the plug-in supports. A developer must write the plug-in using the expected function names. A string starting with "F:" is a fixed number of elements (eight) listing the function names that the plug-in developer expects the protocol server to call. When using the "F" option, the position 8 function (esefifReset) must be terminated with a comma. A developer will write up to nine functions. Any plug-in function can be renamed except the initialization function, which must be named "esefifInit".

Table 4-4

Service Syntax Required Position Default Function Name


Yes

1

EsefifClose


Yes

2

esefifRegister


No

3

esefifSend


No

4

esefifRecv

CONNECT

Yes

5

esefifConnect

ENVELOPE

No

6

esefifEnvelope

MESSAGE

No

7

esefifMessage

RESET

Yes

8

esefifReset


Consider a plug-in written to look at the envelope and message of every message passed to it. The following two examples would be equivalent service strings for this plug-in:


"E:CONNECT,ENVELOPE,MESSAGE,RESET"
"F: , , , , esefifConnect, esefifEnvelope, esefifMessage, esefifReset,"

Note the terminating comma after esefifReset.

The following example would tell the protocol server calling the plug-in that the plug-in function names are different from the default.


"F:pi_close, pi_reg, pi_send, pi_recv, pi_connect, pi_env, pi_msg, pi_reset,"
scanflags (IN)

This is a text string retrieved from the scanner flags field for plug-in (filter) policy management pages. These flags provide a way to pick up necessary administration variables.

sysflags (IN)

This is a text string describing the system flags, or flags that are understood by the mail protocol server. The current release of the plug-in API only understands a single flag, repairmsg, with possible values of 1 and 0 (e.g. repairmsg=1). If the value is 1 then a protocol server will assume that it may get a request from the plug-in to modify a message. Otherwise it will ignore a request by the plug-in to receive a modified message.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

The initialization function is the one function written by the plug-in developer that must be called "esefifInit". This function must always be implemented.


esefifClose()

void esefifClose(void *ifgctx);

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

Returns

none

esefifRegister()

int esefifRegister(void *ifgctx, 
                   int (*cb)(void*), 
                   void*,void*),
                   unsigned int flags);

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

cb (IN)

This is the function pointer to one of the twelve framework functions.

flags (IN)

An integer specifying which function pointer is being passed in.

Table 4-5 Flags for esefifRegister() function

Flag Framework Function

ESEFIF_CALLBACK_SENDMSG

Send a message to the plug-in

ESEFIF_CALLBACK_RECVMSG

Receive modified message from the plug-in

ESEFIF_CALLBACK_GETENVELOPE

Get envelope information

ESEFIF_CALLBACK_GETMSGSIZE

Get the size of a message

ESEFIF_CALLBACK_GETMSGID

Get the mail store message ID of a message

ESEFIF_CALLBACK_FREE

Free memory that was allocated by the framework

ESEFIF_CALLBACK_SETVERSION

Set the plug-in history definition text

ESEFIF_CALLBACK_GETMSGHDR

Get the message's top-level header

ESEFIF_CALLBACK_WRITELOG

Log a message in the protocol server log file

ESEFIF_CALLBACK_ALLOC

Allocate memory

ESEFIF_CALLBACK_ADDRCPT

Add recipients to the recipient list

ESEFIF_CALLBACK_DELRCPT

Delete recipients from the recipient list

ESEFIF_CALLBACK_GETPOLICYID

Get policy identifier of the archive plug-in, if any


Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

The protocol server will call the registration function of a plug-in once for each framework function. The plug-in should update its global context with each function pointer.


esefifSend()

int esefifSend(void *ifgctx,
               char *buf,
               int buflen);

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

buf (IN)

This is a pointer to the block of memory containing a chunk of the message.

buflen (IN)

The size of each chunk of the message.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

This function is a wrapper used by the Oracle mail protocol server to send a message to the plug-in. In order to not have to build a complete message (which could be megabytes in size) and then copy it over to the library, the scanning interface uses this send function to retrieve the message in chunks. The buflen parameter specifies the size of each chunk.

This function must be written to receive the message from the sending protocol server. The protocol server will call this wrapper function within a loop, each time passing it "buflen" bytes of the mail message until the complete message has been sent. The protocol server will then stop calling this function and the framework function will return.


esefifRecv()

int esefifRecv(void *ifgctx,
               char *buf,
               int *buflen);

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

buf (OUT)

This is a pointer to the block of memory containing a piece of the message.

buflen (IN/OUT)

The protocol server will set buflen to the maximum memory size it will accept, when it calls this function. The plug-in sets this value to the size of the buffer being returned. The protocol server will continue to call esefifRecv() until this function returns a NULL buf and a buflen of zero.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

This function is a wrapper function used by the Oracle mail protocol server to receive a message from the plug-in. In order to not have to allocate memory and move a complete message all at once (which could be megabytes in size), the interface uses this receive function to copy the message in chunks. This version of the interface sends in a maximum buffer size of 1024 bytes.

This function must be written to send a modified or cleaned message to the receiving protocol server. When a plug-in needs to return a modified message, it will call the framework function for sending the message. The protocol server will call this wrapper function within a loop, each time sending a piece of the mail message until the complete message has been sent. The protocol server will then stop calling this function and the framework function will return.


esefifConnect()

int esefifConnect(void *ifgctx,
                  void **iflctx,
                  void *efcbctx,
                  char *host,
                  char *ip,
                  int flags,
                  char *errmsg) 

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

iflctx (OUT)

This is a pointer to the local context of this connection, which will hold information to be passed between processing (CONNECTION, ENVELOPE, MESSAGE, RESET).

efcbctx (IN)

This is a pointer to the filter framework context. This context is only sent to the plug-in as a part of the mandatory CONNECT service. The context needs to be stored in the local context of this connection so that it can be made available to the other services. A service cannot call a framework function without the filter framework context.

host (IN)

This is a text string containing the host name of the client (or remote process) that is contacting the protocol server. If the mail protocol server calling the plug-in is the housekeeper, which does not accept connections from remote clients or processes, then this is filled the name of the local host running the housekeeper.

ip (IN)

This is a text string containing the decimal representation for the 32-bit IPv4 address ("nnn.nnn.nnn.nnn") of the client (or remote process) Internet protocol address that is contacting the protocol server. If the mail protocol server calling the plug-in is the housekeeper, which does not accept connections from remote clients or processes, then this is filled the name of the local host IP address.

flags (IN)

Unused. Will always be zero.

errmsg (IN/OUT)

The mail protocol server passes a pointer to a 512-byte buffer that holds error message text, should the plug-in need to reject the connection.

Returns

ESEFIF_SUCCESS     Success - Allow connection
ESEFIF_REJECT      Failure - Reject connection
ESEFIF_ERROR       Error

Comments

Information available to the plug-in consists only of the bind information for the connection.

The plug-in developer must implement this service. The protocol server calls this function first, once for each session connection from a client or other protocol server. In the case of the housekeeper protocol server, the connect function will be called once (and first) for each message.

The plug-in developer must allocate a context (iflctx), for the scope of the connection, which will be passed to all other plug-in processes when the mail protocol server calls them. It must also populate the context with the pointer to efcbctx so these subsequent services have access to all the framework functions.

Framework functions available to the plug-in developer:

ESEFIF_CALLBACK_FREE - Free Memory

ESEFIF_CALLBACK_WRITELOG - Log a message to the logfile

ESEFIF_CALLBACK_ALLOC - Allocate Memory


esefifEnvelope()

int esefifEnvelope(void *ifgctx,
                   char *envinfo,
                   unsigned int flags,
                   char *errmsg)

Purpose

Parameters

ifgctx (IN)

This is a pointer to the connection context of the plug-in. This is the same context allocated and populated in the esefifConnect() function.

envinfo (IN)

This is a pointer to the envelope information.

flags (IN)

These flags can be used to specify envelope properties, such as sender-only or rcpts-only.

0 ALL env info (default).
 1 HOST (envinfo will be hostname)
 2 SENDER (envinfo will be sender)
 3 RECIPIENT (envinfo will be <rcpt1>,<rcpt2>,...
 4 AUTH (envinfo will be auth info)
 5 HELO/EHLO DOMAIN (envinfo will be domain).
errmsg (IN / OUT)

The mail protocol server passes a pointer to a buffer holding error message text that would be returned to the remote client or process in the case when the plug-in needs to reject the message based upon envelope information. The maximum buffer length is 512 bytes.

Returns

ESEFIF_SUCCESS     Success - Allow Login
ESEFIF_REJECT      Failure - Reject Login
ESEFIF_ERROR       Error

Comments

This is the service function that Oracle mail protocol servers use to send envelope information to the plug-in. Envelope information is only persistent for the life of the message as it passes through a message transfer agent (MTA). Only the Oracle SMTP and LIST SERVER processes would have this information or call this function. The envelope information is returned in a single buffer, which must be parsed and understood by this function.

The buffer contains up to five different pieces of information. Each piece of information is a keyword/value pair in the syntax "<keyword>=<value>". Pairs are separated by the pipe (|) character. One field, the recipient list, can contain multiple values. In this case, each value is separated by the comma (,) character.

host=<hostname>|mailfrom=<sender info>|rcptto=(<rcpt1>,<rcpt2>...)[|authinfo=<authinfo>]|domain=<helo domain>[|resrcpt=(<rrcpt1>,<rrrcpt2>...)]

Table 4-6 Description of Envelope Keywords

Keyword Description

Host

The host name making the connection with the server and requesting the mail to be sent. An SMTP server configured to verify the connect request with a reverse DNS lookup will populate this field with the value returned by the DNS. Otherwise, this will contain the text for a decimal represented IPv4 address.

mailfrom

The sender's email address. This is the fully qualified email address from whom the message claims to be sent

rcptto

A list of comma delimited, fully qualified email addresses. The list in its entirety is enclosed in parentheses

authinfo

The fully qualified email address of the authenticated sender. This keyword/value pair is a part of the envelope only when the connection is authenticated. Optional.

domain

The helo or ehlo domain of the remote client or MTA.

resrcpt

A list of comma delimited, fully qualified resolved email addresses. The list in its entirety is enclosed in parentheses.


The header buffer will not include white space. The four keywords are in lower case; the order is always be the same (host, mailfrom, rcptto, [authinfo], domain). The "authinfo" field is optional, and is only provided if the remote system has authenticated the SMTP connection. The "rcptto=" list will always be enclosed in parentheses, even when the mail is only being delivered to a single recipient.

Note: When a plug-in reaches the INCOMING high-level event control point, the "rcptto" list will include all recipients. However, the list will be unresolved. The list will include email addresses, and public distribution lists. When the plug-in reaches either the OUTGOING or LOCAL high-level event control points, the "rcptto" list will be completely resolved but could be a subset of the complete recipient list. If OUTGOING is reached, only those recipients external to the system will be listed. If LOCAL is reached, only those recipients in local domains will be listed.

Note: Adding and deleting recipient addresses are only available at the INCOMING high-level event control point.

Framework functions available to plug-in developer:

ESEFIF_CALLBACK_FREE - Free Memory

ESEFIF_CALLBACK_WRITELOG - Log message to logfile

ESEFIF_CALLBACK_ALLOC - Allocate Memory

ESEFIF_CALLBACK_ADDRCPT - Add Recipient

ESEFIF_CALLBACK_DELRCPT - Delete Recipient


esefifMessage()

int esefifMessage(void *ifgctx,
                  unsigned int flags,
                  char *errmsg)

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

flags (IN)

Unused. Always zero.

errmsg (IN / OUT)

The mail protocol server passes a pointer to a 512-byte buffer holding error message text that would be returned to the remote client or process in the case when the plug-in needs to reject the message based upon envelope information.

Returns

ESEFIF_SUCCESS     Success - Allow Message
ESEFIF_REJECT      Failure - Reject Message
ESEFIF_MODIFIED    Allow the modified message
ESEFIF_ERROR       Error

esefifReset()

int esefifReset(void *ifgctx,
                unsigned int flags,
                char *errmsg)

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

flags (IN)

ESEFIF_RESET_MESSAGE The remote site has issued a temporary reset
ESEFIF_RESET_CLIENT This reset routine is being called at the end of a connection. The connection could be closed due to permanent network error (TCP/IP reset).
errmsg (IN / OUT)

The mail protocol server passes a pointer to a 512-byte buffer holding error message text that would be returned to the remote client or process in the case when the plug-in needs to reject the message.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

All framework functions are available to the plug-in developer at this service point.


Framework Functions

The plug-in framework provides various callback services to be used when developing plug-ins. Function pointers passed to the esefifRegistration() function are used to tell the plug-in code how to call these framework functions. Developers can make these functions globally available, either by defining global function pointers or by recording them in the global context for the plug-in. All framework functions share the same interface, each returns an integer, and each takes three void pointers as parameters.

int (*function)(void*, void*,void*);

ESEFIF_CALLBACK_SENDMSG - Send message

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

iflctx (IN)

This is a pointer to the local context of the plug-in.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments


ESEFIF_CALLBACK_RECVMSG - Receive message

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

iflctx (IN)

This is a pointer to the local context of the plug-in.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments


ESEFIF_CALLBACK_GETENVELOPE - Get envelope

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

envinfo (OUT)

This is a pointer to a buffer containing the envelope information. (See "envinfo" parameter in esefifEnvelope() for the buffer syntax).

eflctx (IN)

This is pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

This framework function implicitly asks the framework to allocate memory on behalf of the plug-in. The developer must free the memory "envinfo" points to if this function is called.


ESEFIF_CALLBACK_GETMSGID - Get mail store identifier of a message

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

msgid (OUT)

This is the mail store message identifier for the message.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

Message IDs are Oracle-specific and unique to the mail store. This ID is not the RFC822 GUID of the message. A message is retained only once in each mail store, along with instance records for all recipients of the message who use that mail store. If an email message is sent to two recipients, each on a different mail store, then two copies of the message are stored, one for each store. Each store would have a distinct and different message identifier for the message. Should a plug-in require a globally unique message ID, it should call the framework function for getting the message header and retrieve the RFC822 GUID from the header.


ESEFIF_CALLBACK_FREE - Free memory allocated by the framework

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

buffer (IN)

This is a pointer to the memory to be freed.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments


ESEFIF_CALLBACK_SETVERSION - Set Version definition

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

definition (IN)

This is a character string that contains the definition of the knowledge base of virus definitions. Maximum length of 240 characters.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

Setting the history definition will create a record in the mail store schema. The record description is:

  1. SCANNED - An Oracle date for when this framework function was called.

  2. MSG_ID - The mail store message identifier for the message

  3. SCANNER - The vendor name of the plug-in

  4. DESCRIPTION - This text field

This record can be shared between plug-in instances on multiple mail protocol servers to ensure processing executes only once. For example, a plug-in that scans for viruses at the MTA as a message enters a mail store can create a record with definition text that describes the knowledge base of the virus definitions. The same vendor's plug-in could then scrub the mail store later on and bypass those messages which have already been checked with the same virus definition.


ESEFIF_CALLBACK_GETMSGHDR - Get message header

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

header (OUT)

This is a pointer to a buffer that contains the top-level header.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

Because the protocol server allocates the memory for this buffer, plug-ins that use this function must free the header buffer with the framework Free Memory function.


ESEFIF_CALLBACK_WRITELOG - Write entry in protocol server log file

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

msg (IN)

This is a character string to be logged. The maximum length is 4000 bytes. The log string will have the filter library specified in the module parameter to identify which filter logged the message. The input string is logged as is.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments


ESEFIF_CALLBACK_ALLOC - Allocate memory

Purpose

Parameters

buffer (OUT)

This is a pointer to the global context of the plug-in.

buflen (IN)

This is a pointer to the local context of the plug-in.

efgctx (IN)

This is a pointer to the global context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments


ESEFIF_CALLBACK_ADDRCPT - Add address to recipient list

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

addr (IN)

Fully qualified email address to be added to the recipient list.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

This function can be called multiple times. Each call will add an additional email address.


ESEFIF_CALLBACK_DELRCPT - Delete address from recipient list

Purpose

Parameters

ifgctx (IN)

This is a pointer to the global context of the plug-in.

ddr (IN)

This is a fully qualified email address to be removed from the recipient list.

eflctx (IN)

This is pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT      Failure

Comments

This function can be called multiple times, each call removing an additional email address.

This framework function only works on envelope information. An address removed from the envelope may still exist in the header of the mail message.


ESEFIF_CALLBACK_GETMSGSIZE - Get size of a mail message

Purpose

Parameters

msgsize (OUT)

Message size in bytes.

eflctx (IN)

This is a pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT     Failure

Comments

The plug-in can determine the size of the message prior to obtaining the message from the framework. This size can be used or buffer allocation for the message. This function is applicable in the context of esefifMessage() and can be called multiple times.


ESEFIF_CALLBACK_GETPOLICYID - Get policy identifier of the archive plug-in

Purpose

Parameters

ifgctx (IN)

A pointer to the global context of the plug-in.

policyid(OUT)

Archive policy identifier.

eflctx (IN)

A pointer to the local context of the framework.

Returns

ESEFIF_SUCCESS     Success
ESEFIF_REJECT     Failure

Comments

The policy identifier should be used to index built by plug-in from the list of policies passed in scanner flags during plug-in initialization to fetch current information related to this policy such as mailbox, xheader. If the plug-in is not associated with any archive policy, -1 is returned as the policy identifier.


Code Samples

Testing a Process Plug-In

To test a filter, run it as a standalone program and send sample message input using the terminal (stdin), with a ctrl-D character to end the input. Once testing is complete, you can configure and use this filter as an OCS filter. This method will reduce troubleshooting time if errors appear in the Mail Server logs due to problems such as incorrect permissions, incorrect reading of input parameters, or incorrect status line in the output from the filter program.

Code Listing for Sample Script

The following C-shell script logs the command line arguments, receives the message from Mail server, saves it to a file and accepts the message by passing a status code of 0. The log file and input message file should be different for different invocations of the executable and they will be created in the same directory as the executable. The directory must have write access for this executable to create these files.

#!/bin/csh
echo `date` >> $0.$$.log
echo "dummyscript started with arguments:" $* >> $0.$$.log
echo "Received Message on stdin:" >> $0.$$.msg

# save the message to a file
cat >> $0.$$.msg

# accept the message
echo "0"
echo `date` >> $0.$$.log
echo "dummyscript accepted the message" >> $0.$$.log

# send version info in the following way
# echo "0 [dummyscriptversion 1.0]"
exit 0

C Plug-in

The following code sample demonstrates how to construct a plug-in to be called by the Mail Protocol Server. The code provides a rudimentary implementation of each of the twelve framework callback functions.

/* Copyright (c) 2005, Oracle Corporation. All rights reserved. */
/*
 
NAME
    dummyif.c - An example dummy scanner/filter interface.
 
DESCRIPTION
    An example dummy scanner/filter interface to illustrate usage:
        - Implements services CONNECT, ENVELOPE, MESSAGE, RESET
        - Handles multiple messages in single connect.
        - Fetches envelope/header/message size/message id from MTA
        - Gets message from MTA.
        - Inserts a dummy header field; If repairmsg flag is on,
          posts this message back to MTA.
        - Sets Version definition.
        - Output is written to /tmp/dummyif.<pid>.out where pid is the
          MTA's process id.
*/
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
 
/*---------------------------------------------------------------------------
   PRIVATE TYPES AND CONSTANTS
---------------------------------------------------------------------------*/
/* building shared library
** compile with -G option: cc -G dummyif.c -o dummyif.so
** use -g option for debugging: cc -g -G dummyif.c -o dummyif.so
*/
 
#define ESEF_VSCANIF_SUCCESS 0
#define ESEF_VSCANIF_FAIL 1
#define ESEF_VSCANIF_REPAIR 2
#define ESEF_VSCANIF_ERROR 3
 
typedef struct dummy_gcx
{
    /* MTA's call back functions */
    int (*frsend)(void*, void*,void*);
    int (*frrecv)(void*, void*,void*);
    int (*frgetenvl)(void*, char **,void*);
    int (*frgetmsgsize)(void*, int *,void*);
    int (*frgetmsgid)(void*, int *,void*);
    int (*frfreemem)(void*, void*,void*);
    int (*frsetversiondef)(void*, char *,void*);
    int (*frgethdr)(void*, char **,void*);
    int (*frlogmsg)(void*, char *,void*);
    int (*frallocmem)(void **, int ,void*);
    int (*fraddrcpt)(void*, char *,void*);
    int (*frdelrcpt)(void*, char *,void*);
    char services[1024];
    void *efgctx;
    char scanflags[256];
    char sysflags[256];
    unsigned int repair;
} dummy_gcx;
 
typedef struct dummy_lcx
{
    signed char *bufp;
    char *envbufp;
    int len;
    int pos;
    dummy_gcx *gctx;
    void *efcbctx;
} dummy_lcx;
 
FILE *fpout;
 
 
/*---------------------------------------------------------------------------
     STATIC FUNCTION DECLARATIONS
 ---------------------------------------------------------------------------*/
 
 
int esefifInit(
    void **ifgctx,
    void *efgctx,
    void **services,
    char *scanflags,
    char *sysflags)
{
    dummy_gcx *gctx;
    int pid;
    char outfile[256];
 
    pid = getpid();
    sprintf(outfile,"/tmp/dummyif.%d.out",pid);
    fpout = fopen(outfile,"w");
    if (!fpout) fpout=stdout;
    fprintf(fpout,"In esefifInit()\n");
 
    gctx = *ifgctx = (void *) calloc(1,sizeof(dummy_gcx));
    gctx->efgctx = efgctx;
 
    if (scanflags) strcpy(gctx->scanflags,scanflags);
    if (sysflags) strcpy(gctx->sysflags,sysflags);
    if (strstr(gctx->sysflags,"repairmsg=1")) gctx->repair = 1;
    fprintf(fpout,"scanflags=%s,sysflags=%s\n",gctx->scanflags,gctx->sysflags);
 
    sprintf(gctx->services,"E:CONNECT,ENVELOPE,MESSAGE,RESET");
    *services = gctx->services;
 
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
void esefifClose(void *ifgctx)
{
    fprintf(fpout, "In esefifClose()\n");
    fflush(fpout);
 
    free(ifgctx);
 
    fclose(fpout);
    return;
}
 
 
int esefifRegister(
    void *ifgctx,
    int (*cb)(void*, void*,void*),
    unsigned int flags)
{
    dummy_gcx *ifgctx1;
 
    fprintf(fpout,"In esefifRegister()\n");
 
    ifgctx1 = (dummy_gcx *) ifgctx;
    switch (flags)
    {
    case 0:
        ifgctx1->frsend = cb;
        break;
    case 1:
        ifgctx1->frrecv = cb;
        break;
    case 2:
        ifgctx1->frgetenvl = (int (*) (void*, char **,void*)) cb;
        break;
    case 3:
        ifgctx1->frgetmsgsize = (int (*) (void*, int *,void*)) cb;
        break;
    case 4:
        ifgctx1->frgetmsgid = (int (*) (void*, int *,void*)) cb;
        break;
    case 5:
        ifgctx1->frfreemem = cb;
        break;
    case 6:
        ifgctx1->frsetversiondef = (int (*) (void*, char *,void*)) cb;
        break;
    case 7:
        ifgctx1->frgethdr = (int (*) (void*, char **,void*)) cb;
        break;
    case 8:
        ifgctx1->frlogmsg = (int (*) (void*, char *,void*)) cb;
        break;
    case 9:
        ifgctx1->frallocmem = (int (*) (void**, int ,void*)) cb;
        break;
    case 10:
        ifgctx1->fraddrcpt = (int (*) (void*, char *, void*)) cb;
        break;
    case 11:
        ifgctx1->frdelrcpt = (int (*) (void*, char *, void*)) cb;
        break;
    default:
        return ESEF_VSCANIF_ERROR;
    }
 
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
int esefifConnect(
    void *ifgctx,
    void **iflctx,
    void *efcbctx,
    char *host,
    char *ip,
    int flags,
    char *errmsg)
{
    dummy_lcx *iflctx1;
    int size=0;
    dummy_gcx *ifgctx1;
 
    fprintf(fpout,"In esefifConnect()\n");
 
    ifgctx1 = (dummy_gcx *) ifgctx;
    ifgctx1->frallocmem((void **)&(iflctx1),sizeof(dummy_lcx),ifgctx1->efgctx);
    memset(iflctx1,0, sizeof (dummy_lcx));
    iflctx1->gctx = ifgctx;;
 
    *iflctx = iflctx1;
    iflctx1->efcbctx = efcbctx;
 
    if (host)
        fprintf(fpout,"esefifConnect(): Host=%s\n",host);
    if (ip)
        fprintf(fpout,"esefifConnect(): IP=%s\n",ip);
 
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
int esefifEnvelope(
    void *iflctx,
    char *envinfo,
    unsigned int flags,
    char *errmsg)
{
 
    fprintf(fpout,"In esefifEnvelope()\n");
    if (envinfo) fprintf(fpout, "esefifEnvelope(): envinfo=%s\n",envinfo);
 
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
int esefifAuth(void *iflctx, char *authinfo, unsigned int flags, char *errmsg)
{
 
    fprintf(fpout,"In esefifAuth()\n");
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
 
int esefifMessage(void *iflctx, unsigned int flags, char *errmsg)
{
    int rc = ESEF_VSCANIF_SUCCESS;
    int msgsize, msgid, size=0;
    char versiondef[128] = "X-Dummy-VirusScan:01192004";
    char *hdr = NULL;
    dummy_gcx *gctx;
    dummy_lcx *lctx;
 
 
    fprintf(fpout,"In esefifMessage()\n");
    lctx = (dummy_lcx *)iflctx;
    gctx = lctx->gctx;
 
    /* SET DUMMY HEADER */
    gctx->frallocmem((void **)&(lctx->bufp), 128, gctx->efgctx);
    lctx->len = 0;
    lctx->pos = 0;
    sprintf((char *)&(lctx->bufp[lctx->len]), "X-Dummy-VirusScan: 1\n");
    lctx->len += 21;
 
    /* GET ENVELOPE */
    fprintf(fpout, "esefifMessage(): calling MTA get envelope\n");
    if (gctx->frgetenvl(gctx,&(lctx->envbufp),lctx->efcbctx))
    {
        fprintf(fpout, "esefifMessage(): error in MTA get envelope\n");
        rc = ESEF_VSCANIF_ERROR;
        goto exit;
    }
    else
    {
        fprintf(fpout, "esefifMessage(): Envelope Received=%s\n",lctx->envbufp);
        fflush(stdout);
        gctx->frfreemem(gctx,lctx->envbufp,gctx->efgctx);
        lctx->envbufp = NULL;
    }
 
    /* GET MESSAGE ID AND SIZE */
    fprintf(fpout, "esefifMessage(): calling MTA msg size and msg Id\n");
    if (gctx->frgetmsgsize(gctx,&msgsize,lctx->efcbctx))
    {
        fprintf(fpout, "esefifMessage(): error in MTA get msg size\n");
        rc = ESEF_VSCANIF_ERROR;
        goto exit;
    }
    else
        fprintf(fpout, "esefifMessage(): MSG SIZE=%d\n",msgsize);
 
    if (gctx->frgetmsgid(gctx,&msgid,lctx->efcbctx))
    {
        fprintf(fpout, "esefifMessage(): error in MTA get msg id\n");
        rc = ESEF_VSCANIF_ERROR;
        goto exit;
    }
    else
        fprintf(fpout, "esefifMessage(): MSG ID=%d\n",msgid);
 
    /* GET MESSAGE HEADER */
    fprintf(fpout, "esefifMessage: calling MTA get header\n");
    if (gctx->frgethdr(gctx, &hdr, lctx->efcbctx))
    {
        fprintf(fpout, "esefifMessage(): error in MTA get header\n");
        rc = ESEF_VSCANIF_ERROR;
        goto exit;
    }
    if (hdr)
    {
        fprintf(fpout, "esefifMessage(): Message Header=%s\n",hdr);
    }
 
    /* GET MESSAGE */
    fprintf(fpout,"esefifMessage(): calling MTA send\n");
    if (gctx->frsend(gctx, lctx, lctx->efcbctx))
    {
        fprintf(fpout,"esefifMessage(): error in MTA send\n");
        rc = ESEF_VSCANIF_ERROR;
        goto exit;
    }
 
    if (gctx->repair)
    /* if repair mode is on - post message with additional header field */
    {
        /* MTA RECV */
        rc = 2;
        fprintf(fpout,"esefifMessage(): calling MTA recv\n");
        if (gctx->frrecv(gctx, lctx, lctx->efcbctx))
        {
            fprintf(fpout,"esefifMessage(): error in MTA recv\n");
            rc=ESEF_VSCANIF_ERROR;
            goto exit;
        }
    }
 
    /* set version def */
    if (gctx->frsetversiondef(gctx,versiondef,lctx->efcbctx))
    {
        fprintf(fpout,"esefifMessage(): error in MTA set version definition\n");
        rc=ESEF_VSCANIF_ERROR;
        goto exit;
    }
 
    exit:
        if (lctx->bufp) 
        {
            gctx->frfreemem(gctx,lctx->bufp,gctx->efgctx);
            lctx->bufp = NULL;
        }
        if (lctx->envbufp) {
            gctx->frfreemem(gctx,lctx->envbufp,gctx->efgctx);
            lctx->envbufp = NULL;
        }
 
        /* if header contains "virus" treat it as one
           for negative testing */
        if (hdr) 
        {
            if (strstr(hdr, "virus"))
            rc = ESEF_VSCANIF_FAIL;
            gctx->frfreemem(gctx,hdr,gctx->efgctx);
        }

        fflush(fpout);
        return rc;
}
 
int esefifSend(void *iflctx, char *buf, int buflen)
{
    dummy_lcx *lctx;
    dummy_gcx *gctx;
    signed char *bufp;
 
    fprintf(fpout,"In esefifSend()\n");
    
    lctx = (dummy_lcx *) iflctx;
    gctx = lctx->gctx;
    fprintf(fpout,"esefifSend(): buffer size=%d buffer=%s\n",buflen,buf);
    fflush(fpout);
    bufp = lctx->bufp;
    gctx->frallocmem((void **)&(lctx->bufp), (lctx->len+buflen),                              (lctx->gctx->efgctx));
    memcpy(lctx->bufp,bufp,lctx->len);
    gctx->frfreemem(gctx, bufp, gctx->efgctx);
    memcpy(&(lctx->bufp[lctx->len]), buf, buflen);
 
    lctx->len += buflen;
 
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
 
int esefifRecv(void *iflctx, char *buf, int *buflen)
{
    dummy_lcx *lctx;
    dummy_gcx *gctx;
 
    fprintf(fpout,"In esefifRecv()\n");
 
    lctx = (dummy_lcx *) iflctx;
    gctx = lctx->gctx;
    if (lctx->len > *buflen)
    {
        memcpy(buf, &(lctx->bufp[lctx->pos]), *buflen);
        lctx->len -= *buflen;
        lctx->pos += *buflen;
    }
    else if (lctx->len > 0)
    {
        memcpy(buf, &(lctx->bufp[lctx->pos]), lctx->len);
        *buflen = lctx->len;
        lctx->pos += lctx->len;
        lctx->len =0;
    }
    else
    {
        *buflen = 0;
        gctx->frfreemem(gctx,lctx->bufp,gctx->efgctx);
        lctx->bufp = NULL;
    }
 
    buf[*buflen] = '\0';
    fprintf(fpout,"esefifRecv(): buffer size=%d buffer=%s\n", *buflen, buf);
 
    fflush(fpout);
    return *buflen;
}
 
 
int esefifReset(void *iflctx, unsigned int flags, char *errmsg)
{
    dummy_lcx *lctx;
    dummy_gcx *gctx;
 
    fprintf(fpout,"In esefifReset()\n");
    lctx = (dummy_lcx *) iflctx;
    gctx = lctx->gctx;
    if (lctx->bufp)
    {
        gctx->frfreemem(gctx, lctx->bufp, gctx->efgctx);
        lctx->bufp = NULL;
    }
    if (lctx->envbufp)
    {
        gctx->frfreemem(gctx, lctx->envbufp, gctx->efgctx);
        lctx->envbufp = NULL;
    }
    lctx->len = 0;
    lctx->pos = 0;
    if (flags == 1)
    {
        gctx->frfreemem(gctx, lctx, gctx->efgctx);
    }
    fflush(fpout);
    return ESEF_VSCANIF_SUCCESS;
}
 
/* end of file dummyif.c */