[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7 Using Guile Actions

Guile is the GNU’s Ubiquitous Intelligent Language for Extensions. It provides a Scheme interpreter conforming to the R5RS language specification. GNU Anubis uses Guile as its extension language.

This section describes how to write GNU Anubis actions in Scheme. It assumes that the reader is sufficiently familiar with the Scheme language. For information about the language, refer to Top in Revised(5) Report on the Algorithmic Language Scheme. For more information about Guile, See Overview in The Guile Reference Manual.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.1 Defining Guile Actions

A Guile action is defined as follows:

(define (function-name header body . rest)
 ...)

Its arguments are:

header

List of message headers. Each list element is a cons

(name . value)

where name is the name of the header field, and value is its value with final CRLF stripped off. Both name and value are strings.

body

A string containing the message body.

rest

Any additional arguments passed to the function from the configuration file (see section Invoking Guile Actions). This argument may be absent if the function is not expected to take optional arguments.

The function must return a cons whose car contains the new message headers, and cdr contains the new message body. If the car is #t, it means that no headers are changed. If the cdr is #t, it means that the body has not changed. If the cdr is #f, Anubis will delete the entire message body.

As the first example, let’s consider a no-operation action, i.e. an action that does not alter the message in any way. It can be written in two ways:

(define (noop-1 header body)
  (cons header body))
  
(define (noop-2 header body)
  (cons #t #t))

The following example is a function that deletes the message body and adds an additional header:

(define (proc header body)
  (cons (append header
                (cons "X-Body-Deleted" "yes"))
        #f))

Let’s consider a more constructive example. The following function checks if the Subject header starts with string ‘ODP:’ (a Polish equivalent to ‘Re:’), and if it does, replaces it with ‘Re:’. It also adds the header

X-Processed-By: GNU Anubis

Additionally, an optional argument can be used. If it is given, it will be appended to the body of the message.

(define (fix-subject hdr body . rest)
  "If the Subject: field starts with characters \"ODP:\", replace
them with \"Re:\".
If REST is not empty, append its car to BODY"
  (cons (append
         (map (lambda (x)
                (if (and (string-ci=? (car x) "subject")
                         (string-ci=? (substring (cdr x) 0 4) "ODP:"))
                    (cons (car x)
                          (string-append "Re:"
                                         (substring (cdr x) 4)))
                    x))
              hdr)
         (list (cons "X-Processed-By" "GNU Anubis")))
        (if (null? rest)
            #t
            (string-append body "\n" (car rest)))))

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.2 Invoking Guile Actions

Guile actions are invoked from the RULE section using the guile-process command. Its syntax is:

Scheme Function: function args

Arguments:

function

The name of the Guile function to be invoked.

args

Additional arguments. These are passed to the function as its third argument (rest).

To pass keyword arguments to the function, use the usual Scheme notation: ‘#:key’.

As an example, let’s consider the invocation of the fix-subject function, defined in the previous subsection:

guile-process fix-subject <<-EOT
                                ----------
                                Kind regards,
                                Antonius Block
                          EOT

In this example, the additional argument (a string of three lines) is passed to the function, which will add it to the message of the body.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.3 Support for ROT-13

The ROT-13 transformation is a simple form of encryption where the letters A-M are transposed with the letters L-Z. It is often used in Usenet postings/mailing lists to prevent people from accidentally reading a disturbing message.

GNU Anubis supports ROT-13 via a loadable Guile function. To enable this support, add the following to your GUILE section:

guile-load-program rot-13.scm

Then, in your RULE section use:

Scheme Function: rot-13 keyword-arguments

The command accepts the following keyword-arguments:

#:body

Encrypt the entire body of the message

#:subject

Encrypt the ‘Subject’ header.

For example:

trigger "rot-13.*body"
 guile-process rot-13 #:body
done

trigger "rot-13.*subj"
 guile-process rot-13 #:subject
done

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.4 Remailers Type-I

GNU Anubis supports remailers of type I. The support is written entirely in Scheme. To enable it, you need to specify the following in the GUILE section of your configuration file:

guile-load-program remailer.scm

To send the message via a remailer, use the following command in the RULE section:

Scheme Function: remailer-I keyword-arguments

The keyword-arguments specify the various parameters for the remailer. These are:

#:rrt string

This is the only required keyword argument. It sets the value for the Request Remailing To line. string should be your actual recipient’s email address.

#:post news-group

Adds the ‘Anon-Post-To: news-group’ line, and prepares the message for sending it to the Usenet via a remailer. Note, that this is only possible with remailers that support ‘Anon-Post-To:’ header.

#:latent time

Adds the ‘Latent-Time:’ line, that causes a remailer to keep your message for specified time before forwarding it.

#:random

Adds random suffix to the latent time.

#:header string

Adds an extra header line to the remailed message.

Example:

trigger "remail:(.*)/(.*)"
 guile-process remailer-I \
             #:rrt antonius_block@helsingor.net \
             #:post \1 \
             #:latent \2 \
             #:header "X-Processed-By: GNU Anubis & Remailer-I"
done

Some remailers require the message to be GPG encrypted or signed. You can do so by placing gpg-encrypt or gpg-sign statement right after the invocation of remailer-I, for example:

trigger "remail:(.*)/(.*)"
 guile-process remailer-I \
             #:rrt antonius_block@helsingor.net \
             #:post \1 \
             #:latent \2 \
             #:header "X-Processed-By: GNU Anubis & Remailer-I"
 gpg-sign mykey
done

See section Mail Encryption, for more information on mail encryption in GNU Anubis.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.7.5 Entire Message Filters

There may be cases when you need to use an external filter that processes entire message (including headers). You cannot use external-body-processor, since it feeds only the message body to the program. To overcome this difficulty, GNU Anubis is shipped with ‘entire-msg.scm’ module. This module provides Scheme function entire-msg-filter, which is to be used in such cases.

Scheme Function: entire-msg-filter program [args]

Feeds entire message to the given program. The output from the program replaces message headers and body.

progname

Full pathname of the program to be executed.

args

Any additional arguments it may require.

Suppose you have a program /usr/libexec/myfilter, that accepts entire message as its input and produces on standard output a modified version of this message. The program takes the name of a directory for temporary files as its argument. The following example illustrates how to invoke this program:

BEGIN GUILE
guile-load-program entire-msg.scm
END

BEGIN RULE
guile-process entire-msg-filter /usr/libexec/myfilter /tmp
END

Another function defined in this module is openssl-filter:

Scheme Function: openssl-filter program [args]

This function is provided for use with openssl program. Openssl binary attempts to rewind its input and fails if the latter is a pipe, so openssl cannot be used with entire-msg-filter. Instead, you should use openssl-filter. Its arguments are:

program

Path to openssl binary.

args

Its arguments

See section Using S/MIME Signatures, for an example of use of this function.


[ << ] [ < ] [ Up ] [ > ] [ >> ]

This document was generated on January 6, 2024 using texi2html 5.0.