9.2. Native plugins

There are multiple types of native plugins that can be built working with Halon script (HSL), queue, policies, suspensions and delivery. They should be written as C-compatible libraries (.so). It is possible to build plugins in any language able to provide a C ABI interface. Examples of such languages are C, C++ and the GO language (cgo).

Native plugins are loaded into the Halon MTA from the configuration file’s plugins[] section.

HSL plugins may be developed and tested using the hsh program (see the --plugin option).

Plugins may also be autoloaded if added to the /opt/halon/plugins folder and symlinked from /opt/halon/plugins/autoload/smtpd and /opt/halon/plugins/autoload/hsh folders (may needs to be created).

All functions, defines and types (opaque pointers) used when building the plugin is defined in the HalonMTA.h header file (installed in /opt/halon/include).

There is a distinction between functions that should be implemented by the library and functions that are provided by the caller (MTA). Our naming convention is that all functions that should be provided by the library starts with Halon_ and all functions that are provided by the MTA HalonMTA_.

9.2.1. Exported by plugin

The following functions may be applicable to all plugins.

int Halon_version()

This is the only required function. It must return the value of HALONMTA_PLUGIN_VERSION from the HalonMTA.h header file.

HALON_EXPORT
int Halon_version()
{
        return HALONMTA_PLUGIN_VERSION;
}
bool Halon_init(HalonInitContext *hic)

This function is called by the MTA upon startup. If this function returns false then the MTA will not start. It should be used for initialization on the plugin. The hic argument holds a reference to the init context (which can be used to access the configuration) of the plugin, and it is only valid for the duration of the Halon_init call. Use the HalonMTA_init_getinfo() functions with the hic argument.

HALON_EXPORT
bool Halon_init(HalonInitContext* hic)
{
        return true;
}
bool Halon_early_init(HalonInitContext *hic)

This function is called by the MTA upon startup. If this function returns false then the MTA will not start. It is called before Halon_init(), and before any suspends or policies are loaded (so that it can create queue lists using HalonMTA_queue_list_add()). For all other use-cases Halon_init() should be used.

HALON_EXPORT
bool Halon_early_init(HalonInitContext* hic)
{
        return true;
}
void Halon_config_reload(HalonConfig *hc)

This function is called by the MTA upon configuration reloads (smtpd-app.yaml). It can be used to reload the configuration of the plugin. The hc argument holds a reference to the configuration of the plugin, and it is only valid for the duration of the Halon_config_reload call. Use the HalonMTA_config_object_get() family of functions to work with the configuration.

HALON_EXPORT
void Halon_config_reload(HalonConfig* cfg)
{
}
void Halon_cleanup()

This function is called by the MTA upon shutdown. It should be used for cleaning before unloading the plugin. For example closing connections and joining any threads created by the plugin.

HALON_EXPORT
void Halon_cleanup()
{
}

9.2.1.1. Command plugin

bool Halon_command_execute(HalonCommandExecuteContext *hcec, size_t argc, const char *argv[], size_t argvl[], char **out, size_t *outlen)

This function is called by the MTA when a plugin command request (over protobuf) is directed to this plugin (based on its id). If this function returns false, then out is considered an error message. Otherwise it’s arbitrary successful data (that can be encoded in any format). The out data memory will be owned by the MTA.

HALON_EXPORT
bool Halon_command_execute(HalonCommandExecuteContext* hcec, size_t argc, const char* argv[], size_t argvl[], char** out, size_t* outlen)
{
        if (argc > 0 && strcmp(argv[0], "hello") == 0)
        {
                *out = strdup("world");
                return true;
        }
        return false;
}
bool Halon_plugin_command(const char *in, size_t inlen, char **out, size_t *outlen)

Deprecated in 5.8 by Halon_command_execute()

This function is called by the MTA when a plugin command request (over protobuf) is directed to this plugin (based on its id). If this function returns false, then out is considered an error message. Otherwise it’s arbitrary successful data (that can be encoded in any format). The out data memory will be owned by the MTA.

9.2.1.2. HSL plugin

The following functions are applicable to HSL plugins only (not delivery plugins). HSL plugins are preferred over FFI when writing a new library, specific to the Halon MTA.

bool Halon_hsl_register(HalonHSLRegisterContext *hhrc)

This method is called by the MTA and tooling (hsh and hsl-lint) to register all the HSL functions provided by the plugin. The hhrc argument should be used when calling the HalonMTA_hsl_register_function() function. On error false is returned.

HALON_EXPORT
bool Halon_hsl_register(HalonHSLRegisterContext* hhrc)
{
        HalonMTA_hsl_register_function(hhrc, "myfunc", myfunc);
        return true;
}
void myfunc(HalonHSLContext *hhc, HalonHSLArguments *args, HalonHSLValue *ret)

This is the signature of the function that will be called from HSL. It takes three arguments:

  • hhc is a pointer to the current execution context. This can be used to control execution of the plugin.

  • args is the list of function arguments when calling the function from HSL.

  • ret a reference to the return value (which can be modified). Its default value is None.

void myfunc(HalonHSLContext* hhc, HalonHSLArguments* args, HalonHSLValue* ret)
{
        double n = 123.456;
        HalonMTA_hsl_value_set(ret, HALONMTA_HSL_TYPE_NUMBER, &n, 0);
}

9.2.1.3. Queue plugin

The queue plugin functions are called when a message is picked up from the active queue in order to be able to acquire or account for delivery slots, and also when a delivery is done and the slots should be released (eg. when a estimated concurrency for a destination should be increased or decreased).

bool Halon_queue_pickup_acquire(HalonQueueMessage *hqm)

This method is called by the MTA when a message is picked up from the active queue for delivery. If you need the message’s pickup parameters, use the HalonMTA_message_getinfo() function. This function must be non-blocking. If this function return false, the message is not to be delivered, instead it will be requeued to run the pre-delivery hooks and the Halon_queue_pickup_release() will not be called.

void Halon_queue_pickup_release(HalonQueueMessage *hqm)

This method is called by the MTA when a message’s delivery attempt is done. If you need the message’s pickup parameters, use the HalonMTA_message_getinfo() function. This function must be non-blocking.

9.2.1.4. Delivery plugin

The deliver plugin system provides an interface for custom, non-blocking, non-SMTP delivery methods. It simply replaces the queue’s regular SMTP/LMTP client with a custom sending routine. In other words, it sits inbetween the active queue pickup and the post-delivery script.

void Halon_deliver(HalonDeliverContext *hdc)

This method is called by the MTA when sending using a plugin for delivery. This function must be non-blocking.

HALON_EXPORT
void Halon_deliver(HalonDeliverContext* hdc)
{
        short int status = 250;
        HalonMTA_deliver_setinfo(hdc, HALONMTA_RESULT_CODE, &status, 0);
        HalonMTA_deliver_setinfo(hdc, HALONMTA_RESULT_REASON, "OK", 0);
        HalonMTA_deliver_done(hdc);
}

9.2.2. Exported by MTA

These are functions provided by the MTA.

bool HalonMTA_init_getinfo(HalonInitContext *hic, int type, const void *inval, size_t inlen, void *outval, size_t *outlen)

Get info about the plugin (from within the Halon_init function). The following types are available. No memory is owned by the caller. For most types inval and inlen should be (NULL and 0). On error false is returned.

Type

inval

inlen

outval

outlen

HALONMTA_INIT_CONFIG

NULL

0

&HalonConfig*

n/a

HALONMTA_INIT_APPCONFIG

NULL

0

&HalonConfig*

n/a

HALON_EXPORT
bool Halon_init(HalonInitContext* hic)
{
        HalonConfig* cfg;
        HalonMTA_init_getinfo(hic, HALONMTA_INIT_APPCONFIG, nullptr, 0, &cfg, nullptr);
}
HalonConfig *HalonMTA_config_array_get(HalonConfig *cfg, size_t index)

Get a pointer reference to the index value of an array. If the cfg argument is not an array or the index is out of bound then NULL is returned. The pointer returned from this function must not be freed.

size_t index = 0;
HalonConfig* val;
while ((val = HalonMTA_config_array_get(cfg, index++)))
        /* work with val */;
HalonConfig *HalonMTA_config_object_get(HalonConfig *cfg, const char *property)

Get a pointer reference to the property value of a map. If the cfg argument is not a map or the property doesn’t exist then NULL is returned. The pointer returned from this function must not be freed.

HalonConfig* value = HalonMTA_config_object_get(cfg, "key");
const char *HalonMTA_config_string_get(HalonConfig *cfg, size_t *outlen)

Get a pointer reference to the scalar value of cfg. If the cfg argument is not a scalar then NULL is returned. The pointer returned from this function must not be freed.

HalonConfig* value = HalonMTA_config_object_get(cfg, "key");
if (value)
{
        const char* str = HalonMTA_config_string_get(value, NULL);
        if (str)
                printf("%s\n", str);
}
int HalonMTA_hsl_value_type(const HalonHSLValue *value)

Return the type of the HSL value, the following defines may be returned. For types that cannot be used in HSL plugins HALONMTA_HSL_TYPE_UNSUPPORTED is returned (eg. HSL function or resources).

  • HALONMTA_HSL_TYPE_NONE

  • HALONMTA_HSL_TYPE_BOOLEAN

  • HALONMTA_HSL_TYPE_NUMBER

  • HALONMTA_HSL_TYPE_STRING

  • HALONMTA_HSL_TYPE_ARRAY

  • HALONMTA_HSL_TYPE_FFI_POINTER

  • HALONMTA_HSL_TYPE_FILE

  • HALONMTA_HSL_TYPE_FUNCTION

  • HALONMTA_HSL_TYPE_UNSUPPORTED

bool HalonMTA_hsl_value_get(const HalonHSLValue *value, int type, void *outval, size_t *outlen)

Return the value of a HSL value. The type argument must match the actual type of value. All memory is owned by the value itself and must not be freed, or used after the plugin execution is done. On error false is returned.

Type

outval

outlen

HALONMTA_HSL_TYPE_BOOLEAN

&bool

n/a

HALONMTA_HSL_TYPE_NUMBER

&double

n/a

HALONMTA_HSL_TYPE_STRING

&char*

&size_t (optional)

HALONMTA_HSL_TYPE_FFI_POINTER

&void*

n/a

HALONMTA_HSL_TYPE_FILE

&FILE*

char* string;
size_t stringl;
HalonMTA_hsl_value_get(value, HALONMTA_HSL_TYPE_STRING, &string, &stringl);
HalonHSLValue *HalonMTA_hsl_value_array_get(const HalonHSLValue *value, size_t index, HalonHSLValue **key)

Get a reference to the value and key item of an array based on the index (starts at zero). If index doesn’t exist return NULL is returned and the key is not affected. In order to lookup a specific key based on a value they array has to be iterated.

size_t index = 0;
HalonHSLValue *k, *v;
while ((v = HalonMTA_hsl_value_array_get(value, index, &k)))
{
        printf("%zu: type of k %d => v %d\n", index, HalonMTA_hsl_value_type(k), HalonMTA_hsl_value_type(v));
        ++index;
}
size_t HalonMTA_hsl_value_array_length(const HalonHSLValue *args)

Get the length of the HalonHSLValue array.

HalonHSLValue *HalonMTA_hsl_value_array_find(const HalonHSLValue *value, const char *key)

Get a reference to the value of the key. If key doesn’t exist return NULL is returned.

HalonHSLValue *v = HalonMTA_hsl_value_array_find(value, "mykey");
bool HalonMTA_hsl_value_set(HalonHSLValue *value, int type, const void *inval, size_t inlen)

Set a value of value. For strings the value is copied to HSL. As for the FFI pointer type a new FFIPointer object is created which doesn’t own the memory (if ownership is not changed using the HSL FFI implementation). On error false is returned.

Type

inval

inlen

Comment

HALONMTA_HSL_TYPE_NONE

n/a

n/a

HALONMTA_HSL_TYPE_BOOLEAN

&bool

n/a

HALONMTA_HSL_TYPE_NUMBER

&double

n/a

HALONMTA_HSL_TYPE_STRING

char*

size_t (optional)

HALONMTA_HSL_TYPE_ARRAY

n/a

n/a

HALONMTA_HSL_TYPE_FFI_POINTER

void*

n/a

HALONMTA_HSL_TYPE_EXCEPTION

char*

size_t (optional)

HALONMTA_HSL_TYPE_X509

X509*

n/a

OpenSSL’s X509_free is called on destruction, but not X509_up_ref on initialization

HALONMTA_HSL_TYPE_THIS

HalonHSLContext*

n/a

For HSL objects, return a reference to $this

HALONMTA_HSL_TYPE_COPY

HalonHSLValue*

n/a

Copy a HSL value

HalonMTA_hsl_value_set(value, HALONMTA_HSL_TYPE_STRING, "Hello World", 0);
bool HalonMTA_hsl_value_array_add(HalonHSLValue *value, HalonHSLValue **key, HalonHSLValue **value)

Add a new key and value to an array. If the value isn’t None or an array, then return false. The values are initialized as None and should be set.

HalonHSLValue *k, *v;
HalonMTA_hsl_value_array_add(ret, &k, &v);
HalonMTA_hsl_value_set(k, HALONMTA_HSL_TYPE_STRING, "key", 0);
HalonMTA_hsl_value_set(v, HALONMTA_HSL_TYPE_STRING, "value", 0);

Note

Consecutive calls to HalonMTA_hsl_value_array_add() will invalidate previous return HalonHSLValue pointers, use HalonMTA_config_array_get() by index to receive them again.

bool HalonMTA_hsl_value_to_json(const HalonHSLValue *value, char **out, size_t *outlen)

Convert a HalonHSLValue to a JSON string. If the conversion fails, false is returned and out contains the error message (if any; otherwise null). The memory returned in out must be freed using free();

char* json;
size_t jsonlen;
if (HalonMTA_hsl_value_to_json(HalonMTA_hsl_argument_get(args, 0), &json, &jsonlen))
        printf("%s\n", json);
free(json);
bool HalonMTA_hsl_value_from_json(HalonHSLValue *value, const char *json, char **out, size_t *outlen)

Convert a JSON string to a HalonHSLValue. If the conversion fails, false is returned and out contains the error message (if any; otherwise null). The memory returned in out must be freed using free();

char* err;
size_t errlen;
if (!HalonMTA_hsl_value_from_json(ret, json, &err, &errlen))
{
        if (err) printf("Error: %s\n", json);
        free(err);
}

9.2.2.1. Objects

The C API allows you to create HSL object. An object is a collection of functions and a custom pointer.

HalonHSLObject *HalonMTA_hsl_object_new()

Return a pointer to a HSL object. This object must be freed using HalonMTA_hsl_object_delete() after copied to one or more HSL values using HalonMTA_hsl_value_set().

HalonHSLObject* hho = HalonMTA_hsl_object_new();
HalonMTA_hsl_value_set(ret, HALONMTA_HSL_TYPE_OBJECT, hho, 0);
HalonMTA_hsl_object_delete(hho);
bool HalonMTA_hsl_object_type_set(HalonHSLObject *hho, const char *type)

Set the class name. Used to identify the object.

HalonHSLObject* hho = HalonMTA_hsl_object_new();
HalonMTA_hsl_object_type_set(hho, "MyObject");
HalonMTA_hsl_object_delete(hho);
void HalonMTA_hsl_object_ptr_set(HalonHSLObject *hho, void *ptr, void (*free)(void*));

Set the internal ptr of the object. The ptr may be changed when reusing the same object with HalonMTA_hsl_value_set(). The free function can be used to free the ptr when the HSL object is destroyed.

HalonHSLObject* hho = HalonMTA_hsl_object_new();
HalonMTA_hsl_object_type_set(hho, "MyObject");
HalonMTA_hsl_object_ptr_set(hho, strdup("Hello World"), free);
HalonMTA_hsl_value_set(value1, HALONMTA_HSL_TYPE_OBJECT, hho, 0);
HalonMTA_hsl_object_ptr_set(hho, strdup("Hello World"), free);
HalonMTA_hsl_value_set(value2, HALONMTA_HSL_TYPE_OBJECT, hho, 0);
HalonMTA_hsl_object_delete(hho);
void HalonMTA_hsl_object_register_function(HalonHSLObject *hho, const char *name, HalonHSLFunction *hhf);

Register member function on the object, this hhf function should be a regular HSL function myfunc(). When the hhf function is called HalonMTA_hsl_object_ptr_get() may be used to receive the pointer set by HalonMTA_hsl_object_ptr_set() hence making it an instance function of the object.

void *HalonMTA_hsl_object_ptr_get(HalonHSLContext *hhc)

Get the instance pointer set by HalonMTA_hsl_object_ptr_set() from within a HSL function (myfunc()). If not called within a object a null pointer is returned.

void sayhi(HalonHSLContext* hhc, HalonHSLArguments* args, HalonHSLValue* ret)
{
    char* ptr = (char*)HalonMTA_hsl_object_ptr_get(hhc);
    printf("%s\n", ptr);
    HalonMTA_hsl_value_set(ret, HALONMTA_HSL_TYPE_THIS, hhc, 0);
}

// ...
HalonHSLObject* hho = HalonMTA_hsl_object_new();
HalonMTA_hsl_object_type_set(hho, "MyObject");
HalonMTA_hsl_object_ptr_set(hho, strdup("Hello World"), free);
HalonMTA_hsl_object_register_function(hho, "sayhi", &sayhi);
HalonMTA_hsl_value_set(ret, HALONMTA_HSL_TYPE_OBJECT, hho, 0);
HalonMTA_hsl_object_delete(hho);
void HalonMTA_hsl_object_delete(HalonHSLObject *hho)

Free the HSL object created by HalonMTA_hsl_object_new().

9.2.2.2. Callable

The C API allows you to call HSL function by function pointers (often referred to as callback functions).

HalonHSLFunctionCallable *HalonMTA_hsl_function_callable_new(const HalonHSLContext *hhc, const HalonHSLValue *func)

Return a pointer to a HalonHSLFunctionCallable object. This object must be freed using HalonMTA_hsl_function_callable_delete(). If the func argument is not a callable function pointer this function returns null.

HalonHSLFunctionCallable* hhfc = HalonMTA_hsl_function_callable_new(hhc, func);
HalonMTA_hsl_function_callable_delete(hhfc);
HalonHSLValue *HalonMTA_hsl_function_callable_argument_add(HalonHSLFunctionCallable *hhfc)

Add an argument to be used when invoked using HalonMTA_hsl_function_callable_invoke(). The default value of the argument is none. Previously return HalonHSLValue pointers are invalided when the next argument is requested.

auto hhfc = HalonMTA_hsl_function_callable_new(hhc, func);
HalonMTA_hsl_value_set(
        HalonMTA_hsl_function_callable_argument_add(hhfc),
        HALONMTA_HSL_TYPE_STRING,
        "Hello", 0);
HalonMTA_hsl_value_set(
        HalonMTA_hsl_function_callable_argument_add(hhfc),
        HALONMTA_HSL_TYPE_STRING,
        "World", 0);
HalonMTA_hsl_function_callable_delete(hhfc);
bool HalonMTA_hsl_function_callable_invoke(const HalonHSLFunctionCallable *hhfc, HalonHSLValue **ret)

Invoke the HSL function. This function returns a boolean value where

  • true: ret is the return value of the function

  • false: ret is the exception thrown by the function

The lifetime of the ret pointer is bound to the HalonHSLFunctionCallable and is overwritten by each repeated invocation of this function.

auto ctx = HalonMTA_hsl_function_callable_new(hhc, func);
HalonMTA_hsl_value_set(
        HalonMTA_hsl_function_callable_argument_add(ctx),
        HALONMTA_HSL_TYPE_STRING,
        "Hello", 0);
HalonHSLValue* retval;
if (HalonMTA_hsl_function_callable_invoke(ctx, &retval))
        HalonMTA_hsl_value_set(ret, HALONMTA_HSL_TYPE_COPY, retval, 0);
else
        HalonMTA_hsl_value_set(HalonMTA_hsl_throw(hhc), HALONMTA_HSL_TYPE_COPY, retval, 0);
HalonMTA_hsl_function_callable_delete(ctx);

A sample function pointer in HSL.

myfunc(function($phrase) {
        echo "$phrase World!";
});
void HalonMTA_hsl_function_callable_delete(HalonHSLFunctionCallable *hho)

Free the HalonHSLFunctionCallable object created by HalonMTA_hsl_function_callable_new().

9.2.2.3. HSL plugin

HalonHSLValue *HalonMTA_hsl_argument_get(const HalonHSLArguments *args, size_t index)

Get the function call argument based on index (starting at zero). If the index doesn’t exists then NULL is returned.

size_t index = 0;
HalonHSLValue *a;
while ((a = HalonMTA_hsl_argument_get(args, index)))
{
        printf("%zu: type of a %d\n", index, HalonMTA_hsl_value_type(a));
        ++index;
}
size_t HalonMTA_hsl_argument_length(const HalonHSLArguments *args)

Get the length of the HalonHSLArguments list.

HalonHSLValue *HalonMTA_hsl_throw(HalonHSLContext *hhc)

Get a pointer to the exception value that will be thrown when returning from the function. Any HSL type may be thrown. This superseeds any change to the return value.

void example(HalonHSLContext* hhc, HalonHSLArguments* args, HalonHSLValue* ret)
{
        HalonHSLValue* e = HalonMTA_hsl_throw(hhc);
        HalonMTA_hsl_value_set(e, HALONMTA_HSL_TYPE_EXCEPTION, "An error has occurred", 0); // throw an instance of Exception
        return;
}
void HalonMTA_hsl_suspend(HalonHSLContext *hhc)

This function suspends the current execution of the script (and it doesn’t return until scheduled), allowing other scripts to be executed on the specific thread in a cooperative fashion (M:N threading).

void example(HalonHSLContext* hhc, HalonHSLArguments* args, HalonHSLValue* ret)
{
        std::thread t([hhc] {
                sleep(5);
                HalonMTA_hsl_schedule(hhc);
        });
        HalonMTA_hsl_suspend(hhc);
        // continue here after 5 seconds
        t.join();
}
void HalonMTA_hsl_suspend_return(HalonHSLContext *hhc)

This function suspends the current execution of the script after the plugin function has returned to the MTA from the plugin (and it doesn’t return until scheduled), allowing other scripts to be executed on the specific thread in a cooperative fashion (M:N threading). This function should be used when not possible to suspend the execution inside the plugin itself. This is the eg. case when building plugins in GO (cgo).

func sleepTask(hhc *C.HalonHSLContext)
{
        time.Sleep(5 * time.Seconds);
        C.HalonMTA_hsl_schedule(hhc);
}

//export sleep
func sleep(hhc *C.HalonHSLContext, args *C.HalonHSLArguments, ret *C.HalonHSLValue)
{
        go sleepTask(hhc);
        C.HalonMTA_hsl_suspend_return(hhc);
}
void HalonMTA_hsl_schedule(HalonHSLContext *hhc)

Reschedule the execution of a suspended execution. The script execution will be requeued onto the assigned threadpool queue. This function is thread-safe and may be called at any time (before or after the HalonMTA_hsl_suspend()).

bool HalonMTA_hsl_register_function(HalonHSLRegisterContext *hhrc, const char *name, HalonHSLFunction *func)

Register a function to HSL. Must only be called in Halon_hsl_register(). If func is null the function is obtained by the MTA using dlsym (this is useful when writing plugins in eg. GO (cgo) which doesn’t easily support C function pointers). If func is null, in order to prevent naming conflicts, function could be defined and referenced with a custom namespace eg. “xyz__myfunc”, while the registered function name would only be “myfunc”. On error false is returned.

HALON_EXPORT
bool Halon_hsl_register(HalonHSLRegisterContext* hhrc)
{
        HalonMTA_hsl_register_function(hhrc, "myfunc", myfunc);
        return true;
}
//export Halon_hsl_register
func Halon_hsl_register(hhrc *C.HalonHSLRegisterContext) C.bool {
        C.HalonMTA_hsl_register_function(hhrc, C.CString("myfunc"), nil);
}
bool HalonMTA_hsl_register_static_function(HalonHSLRegisterContext *hhrc, const char *classname, const char *name, HalonHSLFunction *func)

Register a static class function in HSL. Must only be called in Halon_hsl_register(). If must be called after HalonMTA_hsl_register_function() so that the class name (function namespace) is created. If func is null the function is obtained by the MTA using dlsym (this is useful when writing plugins in eg. GO (cgo) which doesn’t easily support C function pointers). If func is null, in order to prevent naming conflicts, function could be defined and referenced with a custom namespace eg. “xyz__myfunc”, while the registered function name would only be “myfunc”. On error false is returned.

HALON_EXPORT
bool Halon_hsl_register(HalonHSLRegisterContext* hhrc)
{
        HalonMTA_hsl_register_function(hhrc, "MyClass", MyClass);
        HalonMTA_hsl_register_static_function(hhrc, "MyClass", "staticfunction", MyClass_staticfunction);
        return true;
}

9.2.2.4. Lists plugin

The list plugin may control the content of lists in the queue policy, queue suspend and queue delivery configurations.

bool HalonMTA_queue_list_add(int type, const char *name);

Add a list, this is usually done in the Halon_early_init() function. The type should be one of the HALONMTA_QUEUE_ defines. The name should be given without the “@” prefix. On error false is returned.

bool HalonMTA_queue_list_delete(int type, const char *name);

Delete a list. On error false is returned.

bool HalonMTA_queue_list_item_add(int type, const char *name, const char *item);

Add an item to a list. In order to apply the change call HalonMTA_queue_list_reload(). On error false is returned.

char *HalonMTA_queue_list_item_get(int type, const char *name, size_t index, size_t *length);

Get an item from a list based on the index (starts at zero). The returned item must be freed by the caller. On error NULL is returned.

bool HalonMTA_queue_list_item_delete(int type, const char *name, const char *item);

Delete an item from a list. In order to apply the change call HalonMTA_queue_list_reload(). On error false is returned.

bool HalonMTA_queue_list_reload(int type, const char *name);

Reload a list making the changes affect the queue policies. On error false is returned.

9.2.2.5. Queue plugin

bool HalonMTA_message_getinfo(HalonQueueMessage *hqm, int type, const void *inval, size_t inlen, void *outval, size_t *outlen)

Get info about a message. The following types are available. No memory is owned by the caller. For most types inval and inlen should be (NULL and 0), but for tags it’s the number index of the tag and for metadata the string key index. On error false is returned.

Type

inval

inlen

outval

outlen

HALONMTA_MESSAGE_TRANSPORTID

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_LOCALIP

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_REMOTEIP

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_REMOTEMX

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_RECIPIENTDOMAIN

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_JOBID

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_RECIPIENTLOCALPART

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_SENDERDOMAIN

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_SENDERLOCALPART

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_TRANSACTIONID

NULL

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_QUEUEID

NULL

0

&size_t

n/a

HALONMTA_MESSAGE_TAGS

&size_t

0

&const char*

&size_t (optional)

HALONMTA_MESSAGE_METADATA

char*

size_t (optional)

&const char*

&size_t (optional)

HALONMTA_MESSAGE_RETRYCOUNT

NULL

0

&size_t

n/a

HALONMTA_MESSAGE_CONTEXT

NULL

0

&HalonHSLValue*

n/a

char *HalonMTA_queue_suspend_add(const char *transportid, const char *localip, const char *remoteip, const char *remotemx, const char *recipientdomain, const char *jobid, const char *tag, double ttl)

Add a suspend based on conditions. If any of the conditions (transportid, localip, remoteip, remotemx, recipientdomain or jobid) is NULL it will match any value. The tag and ttl are optional (and may be set to NULL or 0). The ttl is in seconds. The returned id must be freed by the caller. On error NULL is returned.

bool HalonMTA_queue_suspend_update(const char *id, const char *tag, double ttl)

Update a suspensions based the id. The ttl and ttl are optional (and may be set to NULL or 0). The ttl is in seconds. On error false is returned.

bool HalonMTA_queue_suspend_delete(const char *id)

Delete a suspensions based the id. On error false is returned.

char *HalonMTA_queue_policy_add(int fields, const char *transportid, const char *localip, const char *remoteip, const char *remotemx, const char *recipientdomain, const char *jobid, size_t concurrency, size_t messages, double interval, const char *tag, double ttl)

Add a queue policy for the specific fields (the defines should be binary OR’ed). If any of the conditions (transportid, localip, remoteip, remotemx, recipientdomain or jobid) is NULL it will match any value. The concurrency, messages, interval, tag and ttl are optional and may be set to NULL or 0. The interval and ttl is in seconds. The returned id must be freed by the caller. On error NULL is returned.

Fields

HALONMTA_QUEUE_TRANSPORTID

HALONMTA_QUEUE_LOCALIP

HALONMTA_QUEUE_REMOTEIP

HALONMTA_QUEUE_REMOTEMX

HALONMTA_QUEUE_RECIPIENTDOMAIN

HALONMTA_QUEUE_JOBID

bool HalonMTA_queue_policy_update(const char *id, size_t concurrency, size_t messages, double interval, const char *tag, double ttl)

Update a queue policy based on id. The concurrency, messages, interval, tag and ttl are optional and may be set to NULL or 0. The interval and ttl is in seconds. On error false is returned.

bool HalonMTA_queue_policy_delete(const char *id)

Delete a queue policy based the id. On error false is returned.

9.2.2.6. Delivery plugin

bool HalonMTA_deliver_getinfo(HalonDeliverContext *hdc, int type, const void *inval, size_t inlen, void *outval, size_t *outlen)

Get info about the delivery. The following types are available. No memory is owned by the caller. For most types inval and inlen should be (NULL and 0), but for tags it’s the number index of the tag and for metadata the string key index. On error false is returned.

Type

inval

inlen

outval

outlen

HALONMTA_INFO_MESSAGE

NULL

0

&HalonQueueMessage*

n/a

HALONMTA_INFO_FILE

NULL

0

&FILE*

n/a

HALONMTA_INFO_ARGUMENTS

NULL

0

&HalonHSLValue*

n/a

HALONMTA_INFO_RETURN

NULL

0

&HalonHSLValue*

n/a

FILE* fp;
HalonMTA_deliver_getinfo(hdc, HALONMTA_INFO_FILE, NULL, 0, (void*)&fp, NULL);

char* string;
size_t stringl;
HalonMTA_deliver_getinfo(hdc, HALONMTA_INFO_METADATA, "mykey", 0, &string, &stringl);

HalonHSLValue* value;
HalonMTA_deliver_getinfo(hdc, HALONMTA_INFO_RETURN, NULL, 0, &value, NULL);
HalonMTA_hsl_value_set(value, HALONMTA_HSL_TYPE_STRING, "plugin result data", 0);
bool HalonMTA_deliver_setinfo(HalonDeliverContext *hdc, int type, const void *inval, size_t inlen)

Set the result of the delivery status. When the first property of HALONMTA_RESULT_ or HALONMTA_ERROR_ is set. The other properties will have their default values. On error false is returned.

Type

inval

inlen

default

HALONMTA_RESULT_CODE

&short int

n/a

400

HALONMTA_RESULT_ENHANCED_CLASS

&short int

n/a

0

HALONMTA_RESULT_ENHANCED_SUBJECT

&short int

n/a

0

HALONMTA_RESULT_ENHANCED_DETAIL

&short int

n/a

0

HALONMTA_RESULT_REASON

char*

size_t (optional)

“Error”

HALONMTA_ERROR_TEMPORARY

&bool

n/a

true

HALONMTA_ERROR_REASON

char*

size_t (optional)

“Error”

void HalonMTA_deliver_done(HalonDeliverContext *hdc)

This function should be called when the delivery is completed, and after all info is set (using HalonMTA_deliver_setinfo()). This function can be in any thread. The default result if not changed is a temporary error.

HALON_EXPORT
void Halon_deliver(HalonDeliverContext* hdc)
{
        short int status = 250;
        HalonMTA_deliver_setinfo(hdc, HALONMTA_RESULT_CODE, &status, 0);
        HalonMTA_deliver_setinfo(hdc, HALONMTA_RESULT_REASON, "OK", 0);
        HalonMTA_deliver_done(hdc);
}