Мы — долго запрягаем, быстро ездим, и сильно тормозим.
www.lissyara.su —> документация —> EXIM —> 4.70 —> часть 42

42. Добавляем функцию “local_scan()” в Exim


    В наши дни, когда количество email-червей, вирусов, спама постоянно увеличивается, некоторые сайты хотят увеличить количество проверок сообщений прежде чем примут их.
   Расширение для проверки содержимого сообщений (глава 41)имеет средство для передачи возможности сканирования сообщений на спам и вирусы внешним программам. Вы также можете делать это непосредственно в Exim, через строки расширения и условия
condition в ACL который запускается после команды SMTP DATA ли ACL для не-SMTP сообщений (см. главу 40), но здесь есть ограничения.
   Для поддержки дополнительных настроек в соответствии с требованиями сайта, можно слинковать Exim с функцией проверки частных сообщений, написанной на C. Если вы хотите запустить код написанный на чем то другом, чем C, Вы конечно же можете использовать C stub для вызова функции.
   Функция local scan запускается единожды для каждого входящего сообщения, в тот момент когда Exim собирается принять сообщение. Поэтому эта возможность может использоваться для локальных не-SMTP сообщений также, как и для сообщений пришедших по SMTP.
   Exim применяет таймаут к запросам функции local scan, опция которая задает это, называется
local_scan_timeout. По умолчанию параметр равен 5 минутам. Ноль обозначает «непрерывно». Exim так же настраивает обработчики сигналов для SIGSEGV, SIGILL, SIGFPE, и  SIGBUS перед вызовом функции local scan, для того что бы общие типы некорректного завершения были очевидны. Если время перерыва превышено или получен один из сигналов, входящее сообщение отклоняется с ошибкой по времени, если это SMTP сообщение. Для не-SMTP сообщений сообщение сбрасывается и Exim завершает работу с кодом ошибки. Происшествие отражается в main и reject логах.

42.1 Сборка Exim с использованием функции local_scan()

   Для использования функции local scan, вы должны указать указать местоположение Вашей функции перед сборкой Exim, установкой LOCAL_SCAN_SOURCE в файле Local/Makefile. Рекомендованное место хранения директория Local поэтому можно установить
LOCAL_SCAN_SOURCE=Local/local_scan.c

для примера. Функция должна называться local_scan(). Она вызывается Exim'ом после получения сообщения, перед отправкой кода успешного выполнения. Это после всех запущенных ACL. Код возврата вашей функции контролирует принято ли сообщение или нет. Есть закоментированый шаблон функции (который принимает сообщение) в файле src/local_scan.c_.
   Если вы хотите использовать файл конфигурации Exim'а для установки опций для вашей функции local_scan(), вы должны установить
LOCAL_SCAN_HAS_OPTIONS=yes

в файле Local/Makefile (смотрите раздел 42.3 ниже).

42.2 API для local_scan()

   Вы должны включить эту строку в начале вашего кода:
#include "local_scan.h"

   Этот заголовочный файл определяет количество переменных, других значений и прототип самой функции. Exim написан для использования, практически исключительно, беззнаковых символов (unsigned char) и одна из вещей которую определяет заголовок – сокращение для беззнаковых символов, называемое  uschar. Он так же содержит следующие макро определения, для упрощения отбора символьных строк и указателей на символьные строки.
#define CS   (char *)
#define CCS  (const char *)
#define CSS  (char **)
#define US   (unsigned char *)
#define CUS  (const unsigned char *)
#define USS  (unsigned char **)

   Прототип функции local_scan() это:
extern int local_scan(int fd, uschar **return_text);

   Аргументы следующие:

  • fd – файловый дескриптор для файла который содержит тело сообщения (-D файл). Файл открыт для записи и чтения, но обновление не рекомендуется. Предупреждение: Вы не должны закрывать файловый дескриптор.
       Дескриптор позиционируется на 19 символе в файле, в котором первый символ само тело, потому как первые 19 символов ID сообщения, следующий за ним -D и символ newline. Если вы переместитесь в начало файла, вы должны использовать макрос SPOOL_DATA_START_OFFSET для того что бы сбросить начало данных, чтобы не зависеть отт изменений в последующих версиях.
  • return_text – адрес который вы можете использовать возвратив указатель на текстовую строку в конце функции. Значение на которое указывает при входе - NULL.
       Функция должна возвратить значение
    int, которое является одним из следующих макросов:
  • LOCAL_SCAN_ACCEPT - Сообщение принято. Если вы пропустите назад строку текста, это сохранится с сообщением и будет доступно в переменной $local_scan_data. Никаких символов новых строк не поддерживается (если таковые присутствуют, они буду превращены в пробел) и максимальная длина текста 1000 символов.
  • LOCAL_SCAN_ACCEPT_FREEZE - Ведет себя так же как и LOCAL_SCAN_ACCEPT, за исключением того, что принятое сообщение становиться в очередь без незамедлительной доставки и замораживается.
  • LOCAL_SCAN_ACCEPT_QUEUE - Ведет себя так же как и LOCAL_SCAN_ACCEPT, за исключением того, что принятое сообщение становиться в очередь без незамедлительной доставки.
  • LOCAL_SCAN_REJECT - Сообщение отклонено; возвращаемый текст используется как ошибка, который отсылается обратно отправителю и которое протоколируется. Символы newlines поддерживаются, они разрешают многострочный ответ для SMTP отклонений, но конвертируются в \n в логах. Если никакое сообщение не присвоено, используется Administrative prohibition.
  • LOCAL_SCAN_TEMPREJECT - Сообщение временно отклонено. Возвращаемый текст используется как сообщение об ошибке, так же как и LOCAL_SCAN_REJECT. Если никакое сообщение не присвоено используется Temporary local problem.
  • LOCAL_SCAN_REJECT_NOLOGHDR - Ведет себя так же как и LOCAL_SCAN_REJECT, за исключением того что заголовок отклоненного сообщения не записывается в лог отклонений. Эффект неустановленного rejected_header в выборе логов только для этого отклонения. Если rejected_header уже не установлен (см. обсуждение log_selection в главе 49.15) код тот же самый что и у LOCAL_SCAN_REJECT.
  • LOCAL_SCAN_TEMPREJECT_NOLOGHDR - Этот код – такое же изменение LOCAL_SCAN_TEMPREJECT, как и LOCAL_SCAN_REJECT_NOLOGHDR изменение LOCAL_SCAN_REJECT.
       Если сообщение не было получено интерактивно по SMTP, об отклонениях сообщается  записью в
    stderr или отправкой письма, как сконфигурировано опциями -oe в командной строке.

    42.3 Опции конфигурации для local_scan()

       Возможно использовать установку опции, которая устанавливает значения в статических переменных, в модуле local_scan(). Если вы этого хотите, вы должны иметь строку
    LOCAL_SCAN_HAS_OPTIONS=yes
    

    в файле Local/MakefileLocal/Makefile когда вы  собираете Exim. (Эта строка находится в OS/Makefile-Default, закомментированная). Затем в исходном файле local_scan() вы должны определить статические переменные, для хранения значений и таблицу, определяющую их.
       Таблица должна быть вектором называемым
    local_scan_options, типа optionlist. Каждая точка входа – тройное значение состоящее из имени, типа опции, и указателя на переменную содержащую значение. Точки входа должны следовать в алфавитном порядке. Следуя за local_scan_options, вы должны так же определить значение переменной называемой local_scan_options_count содержащую количество входов в таблицу. Вот краткий пример, демонстрирующий две опции:
    static int my_integer_option = 42;
    static uschar *my_string_option = US"a default string";
    
    optionlist local_scan_options[] = {
      { "my_integer", opt_int,       &my_integer_option },
      { "my_string",  opt_stringptr, &my_string_option }
    };
    
    int local_scan_options_count =
      sizeof(local_scan_options)/sizeof(optionlist);
    

       Значения переменных могут быть изменены Exim'ом из файла конфигурации включением секции local scan, так, как в этом примере:
    begin local_scan
    my_integer = 99
    my_string = some string of text...
    

       Доступные типы данных следующие:

  • opt_bool - Определяет булеву опцию (да/нет). Адрес должен указывать на переменную типа BOOL, которая устанавливается в TRUE или FALSE, которые являются макросами определенными как 1 и 0, соответственно. Если вы хотите определить была ли установлена такая переменная вообще, то вы можете вызвать ее как TRUE_UNSET. (Переменные BOOL – целочисленные, которые могут содержать более двух значений).
  • opt_fixed - Эта опция определяет число с фиксированной точкой (целочисленное). Адрес должен указывать на переменную типа int. Хранимое значение умножается на 1000, так например, значение 1.4142 отрежется и сохранится как 1414.
  • opt_int - Эта опция определяет целое число, адрес должен указывать на переменную типа int. Значение может быть определено в любом целочисленном формате, понимаемым Exim'ом.
  • opt_mkint - То же самое как opt_int, за исключением того, что значение выводится в -bP листинг, если в нем точное число килобайтов и мегабайтов, печатается с суффиксом K или M.
  • opt_octint - Опция тоже определяет число, как целочисленное, только значение интерпретируется всегда как восьмиричное целочисленное. Начинается с цифры 0 и выводится в восьмиричном счислении.
  • opt_stringptr - Определяет значение строки, адрес должен быть указателем на переменную, которая указывает на строку (например, тип uschar *).
  • opt_time - Определяет интервал времени. Адрес должен указывать на переменную типа int. Значение которое туда записывается, число в секундах.
       Если в командной строке за local_scan следует параметр
    -bP, Exim выводит значения всех опций local_scan().

    42.4 Доступные переменные Exim

       Заголовок local_scan.h дает вам доступ к некоторым С переменным. Тут перечислены только те, которые, гарантировано, будут поддерживаться от релиза к релизу. Заметьте, как бы то ни было, вы можете получить любое значение переменной Exim, включая $recipients вызывая функцию expand_string(). Экспортируемые переменные C следующие:

  • int body_linecount - Эта переменная содержит число строк в теле сообщения.
  • int body_zerocount - Эта переменная содержит число бинарных нулей в теле сообщения.
  • unsigned int debug_selector - Это переменная устанавливается в ноль, когда отладка не производится. Иначе – это набор значений отладочных селекторов. Два бита используются в функции  local_scan(); они определяются как макросы:
    — D_v - бит установлен, когда
    -v присутствует в коммандной строке. Эта тестовая опция не на что не влияет, любой вызов может установить ее. Остальные биты могут установить только администраторы.
    — D_local_scan – бит для использования функцией
    local_scan(); устанавливается в +local_scan отладочным селектором. По умолчанию не включается в дефолтовый набор отладочных битов. Таким образом, что бы получить отладочный вывод, только когда +local_scan включен, вам нужно написать следующее:
    if ((debug_selector & D_local_scan) != 0)
      debug_printf("xxx", ...);
    

  • uschar *expand_string_message - После неудачной попытки вызвать expand_string() (Возвращаемое значение NULL) переменная expand_string_message содержит сообщение об ошибке, завершается нулем.
  • header_line *header_list - Указатель на цепочку строк заголовка. Структура header_line обсуждается ниже.
  • header_line *header_last - Указатель на последнюю строку заголовка.
  • uschar *headers_charset - Значение опции конфигурации headers_charset.
  • BOOL host_checking - Эта переменная TRUE в момент проверки хоста, инициализируемого опцией -bh командной строки.
  • uschar *interface_address - IP адрес интерфейса который получает сообщения, тип – строка. Значение NULL для локальных сообщений.
  • int interface_port - Порт, на котором было получено это сообщение. При тестировании с опцией командной строки -bh, значение этой переменной равно -1, кроме случая когда порт был определён через опцию -oMi.
  • uschar *message_id - Переменная содержащая идентификаторы сообщений Exim'а для входящих сообщений (значение $message_exim_id), заканчивающаяся нулем.
  • uschar *received_protocol - Имя протокола, по которому было получено сообщение.
  • int recipients_count - Число подтвержденных получателей.
  • recipient_item *recipients_list - Список подтвержденных получателей, хранящийся как вектор длины recipients_count. Структура recipient_item обсуждается ниже. Вы можете добавлять получателей вызывая, receive_add_recipient() (см. ниже). Вы можете удалять получателей, убирая их из вектора и исправляя значение в recipients_count. В частности, устанавливая recipients_count в ноль вы удаляете всех получателей. Если вы затем возвратите значение LOCAL_SCAN_ACCEPT, сообщение будет принято, но тут же исчезнет. Для замещения получателей вы можете установить recipients_count в ноль и затем вызвать receive_add_recipient() так часто как это необходимо.
  • uschar *sender_address - Адрес отправителя. Для отвергнутых сообщений это пустая строка.
  • uschar *sender_host_address - IP адрес хоста отправителя. Для локальных сообщений NULL.
  • uschar *sender_host_authenticated - Имя аутентификационного механизма, который был использован, или NULL если сообщение было получено не через SMTP соединение с аутентификацией.
  • uschar *sender_host_name - Имя хоста отправителя, если известно.
  • int sender_host_port - Порт хоста отправителя.
  • BOOL smtp_input - Переменная равна TRUE для всех входящих SMTP, включая BSMTP.
  • BOOL smtp_batched_input - Переменная равна TRUE для входящих BSMTP.
  • int store_pool - Содержимое этой переменной определяет какой пул памяти будет использоваться для новых запросов. (См. секцию 42.8 для более детальной информации).

    42.5 Структура header_line

    Структура header_line, содержит элементы упомянутые ниже. Вы можете добавить дополнительные строки заголовка, вызывая функцию header_add()(см. ниже). Вы можете комментировать (удалять) линии заголовка, устанавливая их тип в *.

  • struct header_line *next - Указатель на следующую строку заголовка, или на NULL, для последней строки.
  • int type - Код идентифицирующий определенные заголовки, которые Exim распознает.
    Коды, печатные символы, документированные в главе 53 этого руководства. Обратите внимание, любая строка заголовка тип которой -
    *, не передается с сообщением. Эта отметка используется для линий заголовка которые были перезаписаны, (например Envelope-sender: header lines). Зачастую, * означает удалено.
  • int slen - Число символов в строке заголовка, включая символы завершения и символы новой строки.
  • uschar *text - Указатель на текст заголовка. Всегда заканчивается символом новой строки, сопровождаемый нулевым байтом. Внутренние символы новой строки сохраняются.

    42.6 Структура recipient_item

    Структура recipient_item содержит следующие элементы:

  • uschar *address - Указатель на адрес получателя, который был получен.
  • int pno - Используется Exim'ом позже в обработке, когда главные адреса созданы опцией one_time. Несущественна, в то время, когда local_scan() работает, и должен содержать всегда -1 на этом этапе.
  • uschar *errors_to - Если значение не NULL, отталкивет сообщение из-за невозможности доставки получателю по адресу который содержит. Другими словами отвергает отправителя конверта для одного адресата (Сравните с errors_to в общих опциях маршрутизации). Если функция local_scan() устанавливает поле errors_to неквалифицированному адресу, Exim квалифицирует используя домен из qualify_recipient. Когда функция local_scan() вызвана, поле errors_to содержит NULL для всех адресатов.

    42.7 Доступные функции Exim

       Заголовок local_scan.h дает вам доступ к некоторому числу функций Exim. Здесь представлены только те, которые гарантированно будут поддерживаться от релиза к релизу.
    pid_t child_open(uschar **argv, uschar **envp, int newumask, int *infdptr, int *outfdptr,   BOOL make_leader)
       Эта функция создает дочерний процесс, который запускает команду определенную в
    argv. Окружение этого процесса определено в envp, который может быть NULL, если не передаются переменные окружения. Новое unmask служит для процесса в newumask.
       Пайпы стандартного ввода и вывода нового процесса уже настроены и возвращаются вызвавшему через аргументы
    infdptr и outfdptr. Стандартная ошибка клонируется в стандартный вывод. Если есть дескрипторы для файла «в пути» в новом процессе, то они закрываются. Если последний аргумент TRUE, новый процесс возглавляет группу процессов.
       Функция возвращает pid нового процесса, или -1 если что то пошло не так.

    int child_close(pid_t pid, int timeout)
       Функция ждет, когда дочерний процесс завершится, или таймаут (в секундах). Значение таймаута установленное в 0, означает ждать столько, сколько потребуется. Возвращаемые значения следующие:

  • >= 0 Завершение процесса корректно, возвращаемое значение это статус процесса.
  • < 0 and > –256 Процесс завершен сигналом, и возвращаемое значение сигнал процесса со знаком минус.
  • –256 Время процесса истекло.
  • –257 Произошла какая-то другая ошибка в wait(); errno все еще установлен.

    pid_t child_open_exim(int *fd)
       Функция предоставляет Вам средства создания нового сообщения Exim. (Конечно вы можете всегда вызвать
    /usr/sbin/sendmail сами, если хотите, в этом пакете есть все для вас). Функция создает пайп, форки и подпроцесс который запускается
    exim -t -oem -oi -f <>
    

    и возвращает (через аргумент int *) файловый дескриптор для пайпа который подключен к стандартному вводу. Конечный результат фукции - PID подпроцесса. Затем вы можете написать сообщение файловому дескриптору, с получателями в поле To, Cc: и/или Bcc: строками в заголовке.
       Когда вы закончите, вызовите
    child_close(), подождите пока процесс завершится и получите его статус окончания. Таймаут со значением ноль обычно неплохо в этих обстоятельствах. До тех пор пока вы не сделаете ошибку в адресе получателя, вы должны получать код возврата 0.

    pid_t child_open_exim2(int *fd, uschar *sender, uschar *sender_authentication)
       Эта функция более сложная версия
    child_open(). Команда которая загружает ее:
    exim -t -oem -oi -f sender -oMas sender_authentication
    

       Третий аргумент может быть NULL, в этом случае опция -oMas опущена.

    void debug_printf(char *, ...)
       Это отладочная функция Exim'а, с аргументами как для
    printf(). Вывод производится в поток стандартных ошибок. Если отладка не выбрана вызов debug_printf() не будет иметь эффекта. Обычно вы должны делать вызовы по состоянию селекторов local_scan написав это так:
    if ((debug_selector & D_local_scan) != 0)
      debug_printf("xxx", ...);
    

    uschar *expand_string(uschar *string)
       Интерфейс для расширения строки Exim'а. Возвращаемое значение - расширяемая строка, или NULL, если расширение не произошло. Переменная C
    expand_string_message содержит сообщение об ошибке, после невозможности расширения. Если расширение не меняет строку, возвращаемое значение является указателем на строку ввода. В другом случае, возвращаемое значение указывает на новый блок памяти, который был получен вызовом store_get(). (см. раздел 42.8 ниже, где обсуждается выделение памяти).

    void header_add(int type, char *format, ...)
       Эта функция позволяет добавить дополнительную строку заголовка в конец уже существующей. Первый аргумент – тип, который обычно начинается пробелом. Второй аргумент форматированная строка, и любой номер заменяемых аргументов как для
    sprintf(). Вы можете включать внутренний символ новой строки и вы должны убедится, что строка заканчивается символом новой строки.

    void header_add_at_position(BOOL after, uschar *name, BOOL topnot, int type, char *format,   ...)
       Функция добавляет новую строку заголовка в определенную точку в цепочке заголовков.  Сам заголовок определен как для
    header_add().
       Если
    name NULL, новый заголовок добавляется в конец цепочки, при условии что after TRUE, или в начало, если after FALSE. Если name не NULL, строки заголовка ищутся до первого неудаленного заголовка, который совпадает с именем. Если что то найдено, новый заголовок добавляется до него, если значение after FALSE. Если after TRUE, добавляется новый заголовок после найденного заголовка и любых найденных последующих с таким же именем (даже если они отмечены как deleted). Если нет совпадений с non-deleted заголовком, то опция topnot проверяет где был добавлен заголовок. Если он добавлялся – дополнение на верху, если нет то – внизу. Таким образом, что бы добавить заголовок после всех заголовков с полем Received: или в начало, если нет заголовков Received:, вы должны использовать:
    header_add_at_position(TRUE, US"Received", TRUE,
      ' ', "X-xxx: ...");
    

       Обычно присутствует хотя бы один не удаленный заголовок Received:, но его может не оказаться если received_header_text расширяется пустой строкой.

    void header_remove(int occurrence, uschar *name)
       Функция удаляет строки заголовка. Если
    occurrence равно нулю или отрицательное - заголовок удаляется.  Если occurrence больше нуля, удаляется часть заголовка. Если никаких совпадений не найдено, функция не делает ничего.

    BOOL header_testname(header_line *hdr, uschar *name, int length, BOOL notdel)
       Функция проверяет имеет ли данный заголовок данное имя. Это не просто сравнение строк, потому что непоказываемый пробел допускается между именем и двоеточием. Если аргумент
    notdel TRUE, тогда возвращаемое FALSE применяется для всех deleted заголовков, иначе они не рассматриваются. Например:
    if (header_testname(h, US"X-Spam", 6, TRUE)) ...
    

    uschar *lss_b64encode(uschar *cleartext, int length)
       Эта функция кодирует (base64) строку, которая передаётся по адресу и длине. Текст может содержать байты любого значения включая ноль. Результат возвращается в динамическую память которая динамически получается вызовом
    store_get(). Заканчивается нулем.

    int lss_b64decode(uschar *codetext, uschar **cleartext)
       Функция декодирования  base64 строки. Если аргумент заканчивающаяся нулем base64 строка, и адрес переменной который указывает на результат, находящийся в динамической памяти. Длина декодируемой строки получается после выполнения функции. Если вводимые данные неправильные, то результат -1. Нулевой байт добавляется в конце выводимой строки, для более простого ее определения, как С строки (предполагается что она не содержит собственных нулей). Добавляемый нулевой байт не считается.

    int lss_match_domain(uschar *domain, uschar *list)
       Функция проверяет совпадения в доменном списке. Домены всегда выбираются бессистемно. Возвращемое значение одно из следующих:
    OK      match succeeded
    FAIL    match failed
    DEFER   match deferred
    

       Deffer обычно вызван каким либо поиском, таким как невозможность связаться с базой данных.

    int lss_match_local_part(uschar *localpart, uschar *list, BOOL caseless)
       Функция проверяет совпадения в локальном списке. Третий аргумент контролирует чувствительность к регистру. Возвращаемое значение такое же как и для
    lss_match_domain().

    int lss_match_address(uschar *address, uschar *list, BOOL caseless)
       Эта функция проверяет совпадения для списка адресов. Третий аргумент контролирует чувствительность к регистру. Домены всегда выбираются бессистемно. Возвращаемое значение такое же как и для
    lss_match_domain().

    int lss_match_host(uschar *host_name, uschar *host_address, uschar *list)
       Функция проверяет совпадения в списке хостов. Самое распространенное использование:
    lss_match_host(sender_host_name, sender_host_address, ...)
    

       Пустое поле адреса, совпадает с пустым записью в списке хостов. Если имя хоста  NULL, соответствие названия $sender_host_address ищется автоматически, если название хоста должно совпадать с именем в списке. Возвращаемые значения такие же как и в lss_match_domain(), но в дополнении lss_match_domain() возвращает ERROR в случае, когда имя искалось и не нашлось.

    void log_write(unsigned int selector, int which, char *format, ...)
       Эта функция записывает лог файлы Exim'а. Первый аргумент должен быть 0 (это связано с
    log_selector). Следующий аргумент должен быть LOG_MAIN или LOG_REJECT, или LOG_PANIC или любую их комбинацию (лог. ИЛИ (OR)). Это определяет в какой лог или логи будет записано сообщение. Оставшиеся аргументы – это формат и вставка. Строка не должна включать символов новой строки, даже в конце.

    void receive_add_recipient(uschar *address, int pno)
       Эта функция добавляет дополнительного получателя к сообщению. Первый аргумент – это адрес получателя. Если адрес не квалифицирован (не имеет домена) он квалифицируется с
    qualify_recipient доменом. Второй аргумент должен быть всегда -1.
       Функция не позволяет вам определить частный
    errors_to адрес (как описано в структуре recipient_item выше) потому что это предшествует дополнению поля к структуре. Однако, в последствии легко добавить это значение. Например:
    receive_add_recipient(US"monitor@mydom.example", -1);
    recipients_list[recipients_count-1].errors_to =
    US"postmaster@mydom.example";
    

    BOOL receive_remove_recipient(uschar *recipient)
       Эта удобная функция для удаления названного получателя из списка получателей. Если возвращаемое значение TRUE получатель удален и FALSE если совпадающий получатель не найден. Аргумент должен быть полным e-mail адресом.

    uschar rfc2047_decode(uschar *string, BOOL lencheck, uschar *target, int zeroval, int *lenptr,   uschar **error)
       Эта функция декодирует строку которая закодирована согласно RFC 2047. Обычно это содержимое файлов заголовка. Сперва, каждое
    закодированное слово  декодируется от Q или B кодировки в байтовую строку.  Затем, если представлено имя таблицы кодировки, и если iconv() функция доступна, предпринимается попытка перевести результаты к данной кодовой таблице. Если это сделать не удается, бинарная строка возвращает сообщение об ошибке.
       Первый аргумент – строка которая должна быть дешифрована. Если
    lencheck TRUE, устанавливается максимальная длина MIME слова. Третий агрумент – перекодированое слово, или NULL если перекодировка не удалась.
       Если бинарный ноль попадается в строке, то он заменяется в соответствии с содержимым аргумента
    zeroval. Для использования с заголовками Exim, значение должно быть не ноль, поскольку строки заголовков заканчиваются нулем.
       Функция возвращает результат обработки строки, заканчивающийся нулем; если
    lenptr не NULL, то длина обработки устанавливается в переменную на которую она указывает. Когда zeroval равен 0, lenptr не должен быть NULL.
       Если возникла ошибка функция возвращает NULL и использует
    error аргумент для возврата сообщения об ошибке. Переменная указывающая на error устанавливается в NULL если небыло ошибки; она может быть установлена в не NULL даже когда функция возвращает не NULL значение при удачной расшифровке, но есть проблемы с перекодировкой.

    int smtp_fflush(void)
       Функция используется совместно с
    smtp_printf(), как описано ниже.

    void smtp_printf(char *, ...)
       Аргументы такие же как и у
    printf(); она записывает в выходной поток SMTP. Вы должны использовать эту функцию только когда есть выходной SMTP поток, то есть тогда когда получается через SMTP входящее сообщение, в этом случае smtp_input TRUE, а smtp_batched_input FALSE. Если вам нужно протестировать  сообщение с другого хоста (в противоположность локальному процессу, который использует -bs опцию командной строки) вы можете проверить значение sender_host_address который не NULL если применяется удаленный хост.
       Если SMTP TLS соединение установлено
    smtp_printf() использует функцию вывода TLS, таким образом это может использоваться для всех SMTP соединений.
       Строки которые написаны
    smtp_printf(), внутри local_scan() должны начинаться с правильного кода ответа: 550 если вы собираетесь возвратить LOCAL_SCAN_REJECT, 451 если вы собираетесь возвратить LOCAL_SCAN_TEMPREJECT и 250 в остальных случаях. Поскольку вы пишите начальные строки многострочного сообщения, код может сопровождаться дефисом, что бы показать что это не последняя строчка в коде отклика. Вы должны так же убедиться что строки, которые вы пишите заканчиваются CRLF. Например:
    smtp_printf("550-this is some extra info\r\n");
    return LOCAL_SCAN_REJECT;
    

       Учтите, что вы можете создать многострочный отклик включая символы новой строки в данные возвращаемые через аргумент return_text.
       Добавляемое значение использует
    smtp_printf() для того, что бы вы могли ввести задержки между многократным выводом.
       Функция
    smtp_printf() не использует никакого возвращаемого сообщения об ошибке, потому что она не стирает автоматически идущий вывод и поэтому не проверяет состояние потока. (в главном коде Exim стирание и проверка ошибок отрабатываются когда Exim готов для следующего SMTP соединения). Если вы хотите удалить вывод и проверить ошибки (например, сбрасывая TCP/IP соединение) вы все еще сможете вызвать smtp_fflush(), у которой нет аргументов. Она стирает вывод и возвращает ненулевое значение, при возникновении ошибки.

    void *store_get(int)
       Эта функция получает доступ к управлению внутренней памятью Exim. Она получает новую область памяти, чей размер задан аргументом. Exim завершается, если память исчерпана. Смотрите следующий раздел, где обсуждается выделение памяти.

    void *store_get_perm(int)
       Функция наподобии
    store_get(), но всегда получает память из постоянного пула. Смотрите следующий раздел, где обсуждается выделение памяти.

    uschar *string_copy(uschar *string)
       смотрите ниже

    uschar *string_copyn(uschar *string, int length)
       смотрите ниже

    uschar *string_sprintf(char *format, ...)
       Эти три функции создают строки используя средства динамической памяти Exim'а. Первая делает копию всей строки. Вторая копирует максимальное число символов, переданных во втором аргументе. Третья использует формат и вставку новой строки. В каждом случае результатом является указатель на новую строку в данном пуле памяти. Смотрите следующий раздел, где обсуждается выделение памяти.

    42.8 Больше об обработке памяти Exim'ом

       Нет никакой функции для освобождения памяти, поскольку она не нужна. Динамическая память, которую использует Exim автоматически передается другому сообщению полученному этим же процессом (распространяется только на SMTP подключения – другие методы могут только доставить одно сообщение за раз). После получения последнего сообщения, процесс получения завершается.
       Поскольку память повторно используется, нормальная динамическая память не может быть использована для хранения данных, которые должны быть сохранены более чем число входящих сообщений на том же SMTP соединении. Однако, Exim на самом деле использует два пула динамической памяти, второй не передается и может использоваться для этих целей.
       Если вы хотите выделить память, которая останется доступной для последующих сообщений в том же SMTP соединении, вы должны установить
    store_pool = POOL_PERM
    

    прежде, чем вызовите функцию выделения памяти. Не нужно восстанавливать значение без необходимости; однако если вы хотите вернуться к нормальному пулу, вы можете восстановить прежнее значение store_pool или установить явным образом POOL_MAIN.
       Установка пула, применяется ко всем функциям, которые получают динамическую память, включая
    expand_string(), store_get(), и string_xxx() функции. Есть так же, удобная функция называемая store_get_perm() которая получает блоки памяти из постоянного пула, сохраняя значения store_pool.

    =============
    translated by Andy
    verifying by lissyara
    verifying by Gerk





  •  

      Этот информационный блок появился по той простой причине, что многие считают нормальным, брать чужую информацию не уведомляя автора (что не так страшно), и не оставляя линк на оригинал и автора — что более существенно. Я не против распространения информации — только за. Только условие простое — извольте подписывать автора, и оставлять линк на оригинальную страницу в виде прямой, активной, нескриптовой, незакрытой от индексирования, и не запрещенной для следования роботов ссылки.
      Если соизволите поставить автора в известность — то вообще почёт вам и уважение.

    © lissyara 2006-10-24 08:47 MSK

    Время генерации страницы 0.0486 секунд
    Из них PHP: 37%; SQL: 63%; Число SQL-запросов: 65 шт.
    Исходный размер: 84040; Сжатая: 18258