Скачиваний:
33
Добавлен:
23.12.2021
Размер:
2 Мб
Скачать
☆

Рисунок 16. Одна из функций в документации

Рисунок 17. Одно из перечислений в документации

11

Рисунок 18. Макросы в документации

ЗАКЛЮЧЕНИЕ

В результате выполнения лабораторной работы мы разработали приложение, позволяющее принимать электронные письма с вложенными файлами, используя протокол POP3.

12

ПРИЛОЖЕНИЯ

Далее перечислены приложения в следующем порядке:

1.Файл POP3-библиотеки «pop3_lib/pop3_lib.h» (табл. 2).

2.Файл POP3-библиотеки «pop3_lib/pop3_lib.c» (табл. 3).

3.Сборочный файл POP3-библиотеки «pop3_lib/WinMakefile» /

«pop3_lib/LinuxMakefile» (табл. 4).

4.Файл POP3-клиента «pop3_client.c» (табл. 5).

5.Общий сборочный файл «WinMakefile» / «LinuxMakefile» (табл. 6).

Таблица 2. Файл POP3-библиотеки «pop3_lib/pop3_lib.h»

pop3_lib/pop3_lib.h

/** @file

*@brief POP3 client library

*@author Kovalenko Leonid

*@version 1.00

*

*Клиентская библиотека POP3.

*Позволяет пользователю получать электронные письма с сервера POP3.

*/

#ifndef POP3_LIB_H #define POP3_LIB_H

#include <stddef.h> #include <stdio.h> #include <sys/types.h>

#ifndef SIZE_MAX

///Максимальное значение числа типа size_t.

#define SIZE_MAX ((size_t)(-1)) #endif // SIZE_MAX

///Основная структура данных, которая содержит контекст клиента POP3.

///Определение находится в C-файле.

struct pop3;

/// Структура данных, содержащая письмо. struct pop3_message

{

///Номер письма. size_t n;

///Размер письма. size_t size;

///Заголовки письма.

struct pop3_header *header_list;

///Количество заголовков письма. size_t num_headers;

///Отправитель письма.

char *from;

///Реальный отправитель письма. char *envelope_from;

///Получатели письма.

char *to;

///Получатели копий письма. char *cc;

///Дата письма.

char *date;

///Заголовок письма. char *subject;

///Тело письма.

char *body;

/// Вложения письма.

struct pop3_attachment *attachment_list;

/// Количество вложений в списке вложений. size_t num_attachment;

};

/// Данные вложения, которые помещаются в раздел MIME. struct pop3_attachment

{

13

pop3_lib/pop3_lib.h

///Имя файла вложения. char *name;

///Данные файла.

char *data;

/// Длина данных файла size_t data_len;

};

/// Коды состояния вызова любой из функций библиотеки POP3. enum pop3_status_code

{

///Операция успешно завершена.

POP3_STATUS_OK = 0,

///Не удалось выделить память.

POP3_STATUS_NOMEM = 1,

///Не удалось подключиться к почтовому серверу.

POP3_STATUS_CONNECT = 2,

///Не удалось установить соединение или согласовать TLS-соединение с сервером.

POP3_STATUS_HANDSHAKE = 3,

///Не удалось пройти аутентификацию с указанными учетными данными.

POP3_STATUS_AUTH = 4,

///Не удалось отправить байты на сервер.

POP3_STATUS_SEND = 5,

///Не удалось получить байты от сервера.

POP3_STATUS_RECV = 6,

///Не удалось правильно закрыть соединение.

POP3_STATUS_CLOSE = 7,

///POP3-сервер отправил неожиданный код состояния.

POP3_STATUS_SERVER_RESPONSE = 8,

///Неверный параметр.

POP3_STATUS_PARAM = 9,

/** Указывает последний код состояния в перечислении.

*Используется для проверки границ: status_code >= POP3_STATUS__LAST.

*Не является кодом статуса. */

POP3_STATUS__LAST

};

/// Методы шифрования соединения (с шифрованием TLS / без шифрования). enum pop3_connection_security

{

/** STARTTLS. Сначала подключение без шифрования, затем установка

*зашифрованного соединения (команда STARTTLS). Обычно используется

*при подключении к почтовому серверу через порт 110. */

POP3_SECURITY_STARTTLS = 0,

/** TLS. Подключение с шифрованием. Обычно используется при * подключении к почтовому серверу через порт 995. */

POP3_SECURITY_TLS = 1,

/// Без шифрования. Не рекомендуется при нелокальном подключении.

POP3_SECURITY_NONE = 2

};

/// Специальные флаги контекста клиента POP3. enum pop3_flag

{

/// Печать лога коммуникации клиента и сервера в поток stderr.

POP3_DEBUG = 1,

/** Не проверять TLS сертификат.

*По умолчанию функция подтверждения TLS проверяет, истек ли

*срок действия сертификата или используется самозаверяющий сертификат.

*Любое из этих условий приведет к сбою соединения. Эта опция позволяет

*продолжить соединение, даже если эти проверки не пройдут. */

POP3_NO_CERT_VERIFY = 2

};

/** Открывает соединение с POP3-сервером и возвращает контекст.

* @param[in]

server Имя сервера или

IP адрес.

* @param[in]

port Порт сервера.

 

* @param[in]

connection_security См. @ref pop3_connection_security.

* @param[in]

flags См. @ref pop3_flag.

* @param[in]

cafile Путь к файлу сертификата или NULL (NULL: сертификат в пути по умолчанию).

* @param[out]

pop3 Указатель на новый контекст POP3.

*

По завершении вызывающая сторона должна освободить

*

этот контекст

с помощью @ref pop3_close.

* @return См. @ref pop3_status_code. */

enum pop3_status_code pop3_open(const

char *const server, const char *const port,

 

const

enum pop3_connection_security connection_security,

 

const

enum pop3_flag flags, const char *const cafile,

struct pop3 **const pop3);

/** Аутентифицирует пользователя.

*@param[in] pop3 Контекст клиента POP3.

*@param[in] user Имя пользователя POP3.

*@param[in] pass Пароль пользователя POP3.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_auth(struct pop3 *const pop3, const char *const user,

14

pop3_lib/pop3_lib.h

const char *const pass);

/** Получает количество сообщений в почтовом ящике и размер

*почтового ящика согласно текущему контексту POP3.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open .

*@param[in] pop3 Контекст клиента POP3.

*@param[out] messages_count Число писем.

*@param[out] messages_size Размер почтового ящика.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_stat(struct pop3 *const pop3, size_t *const messages_count, size_t *const messages_size);

/** Получает ответ сервера на команду NOOP.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open .

*@param[in] pop3 Контекст клиента POP3.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_noop(struct pop3 *const pop3);

/** Получает данные об электронных письмах согласно текущему контексту POP3.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open .

*@param[in] pop3 Контекст клиента POP3.

*@param[in] messages_count_arg Число писем.

*@param[out] messages См. @ref pop3_message .

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_list(struct pop3 *const pop3, const size_t messages_count_arg, struct pop3_message **const messages);

/** Получает электронное письмо с адресами, вложениями и заголовками,

*определенными в текущем контексте POP3.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open .

*@param[in] pop3 Контекст клиента POP3.

*@param[in] message_number Номер письма.

*@param[out] message Письмо.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_retr(struct pop3 *const pop3, const size_t message_number, struct pop3_message *const message);

/** Удаляет электронное письмо по ID в текущем контексте POP3.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open .

*@param[in] pop3 Контекст клиента POP3.

*@param[in] message_number Номер письма.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_dele(struct pop3 *const pop3, const size_t message_number);

/** Отменяет удаление электронных писем в текущем контексте POP3.

*Перед этим вызывающая сторона должна вызвать функцию @ref pop3_open , а затем @ref pop3_dele .

*@param[in] pop3 Контекст клиента POP3.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_rset(struct pop3 *const pop3);

/** Закрывает соединение POP3 и освобождает все ресурсы, удерживаемые контекстом POP3.

*@param[in] pop3 Контекст клиента POP3.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_close(struct pop3 *pop3);

/** Возвращает текущий код ошибки.

*@param[in] pop3 Контекст клиента POP3.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_status_code_get(const struct pop3 *const pop3);

/** Очищает текущий код ошибки,

установленный в контексте клиента POP3.

*

@param[in,out] pop3 Контекст

клиента POP3.

*

@return

Код предыдущей ошибки перед очисткой. */

enum pop3_status_code pop3_status_code_clear(struct pop3 *const pop3);

/** Устанавливает код ошибки в контексте клиента POP3 и возвращает его же.

*Это позволяет вызывающей стороне очистить код ошибки до @ref POP3_STATUS_OK ,

*чтобы предыдущие ошибки перестали распространяться. Однако это будет работать

*правильно только для всех ошибок до границы @ref POP3_STATUS__LAST .

*Не сбрасывает код ошибки >= @ref POP3_STATUS__LAST .

*@param[in] pop3 Контекст клиента POP3.

*@param[in] status_code См. @ref pop3_status_code.

*@return См. @ref pop3_status_code. */

enum pop3_status_code pop3_status_code_set(struct pop3 *const pop3,

const enum pop3_status_code status_code);

/** Преобразует код состояния клиента POP3 в описательную строку.

*@param[in] status_code Код состояния.

*@return Строка, содержащая описание @p status_code .

*Вызывающая сторона не должна освобождать или изменять эту строку. */ const char *pop3_status_code_errstr(enum pop3_status_code status_code);

/** Получает сообщение об ошибке от сервера.

*@param[in] pop3 Контекст клиента POP3.

*@return Строка, содержащая сообщение об ошибке от сервера.

15

pop3_lib/pop3_lib.h

* Вызывающая сторона не должна освобождать или изменять эту строку. */ const char *pop3_server_error_response(struct pop3 *const pop3);

#endif // POP3_LIB_H

Таблица 3. Файл POP3-библиотеки «pop3_lib/pop3_lib.c»

pop3_lib/pop3_lib.c

/** @file

*@brief POP3 client library

*@author Kovalenko Leonid

*@version 1.00

*

*Клиентская библиотека POP3.

*Позволяет пользователю получать электронные письма с сервера POP3.

*/

#if defined(_WIN32) || defined(WIN32) /** Если ОС Windows. */

#define POP3_IS_WINDOWS #endif // POP3_IS_WINDOWS

#ifdef POP3_IS_WINDOWS #include <winsock2.h> #include <ws2tcpip.h> #else // POSIX #include <netdb.h>

#include <netinet/in.h> #include <sys/select.h> #include <sys/socket.h> #include <unistd.h> #endif // POP3_IS_WINDOWS

#include <errno.h> #include <limits.h> #include <signal.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <time.h>

#ifdef POP3_OPENSSL #include <openssl/bio.h> #include <openssl/err.h> #include <openssl/ssl.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #endif // POP3_OPENSSL

#include "pop3_lib.h"

/** Используется для анализа ответов от POP3-сервера.

*Например, если сервер отправляет обратно "+OK <message>",

*тогда code будет установлен в POP3_STATUS_OK, text в "+OK <message>". */ struct pop3_command

{

///Код результата (целое число). enum pop3_status_code code;

///Текст ответа.

char *text;

};

/** Коды возврата для интерфейса getdelim,

*который позволяет вызывающей стороне проверить,

*могут ли быть обработаны другие строки с разделителями. */ enum str_getdelim_retcode

{

///Ошибка при обработке getdelim.

STRING_GETDELIMFD_ERROR = 0,

///Обнаружил новую строку и в настоящее время не может читать больше строк.

STRING_GETDELIMFD_DONE = 1

};

/** Структура данных для буфера чтения и синтаксического анализа строк. * Помогает получить и проанализировать строки ответа сервера. */

struct str_getdelimfd

{

///Буфер чтения, который может включать байты после разделителя. char *_buf;

///Количество выделенных байтов в буфере чтения.

16

pop3_lib/pop3_lib.c

size_t _bufsz;

///Количество фактически сохраненных байтов в буфере чтения. size_t _buf_len;

///Текущая строка, содержащая текст до разделителя.

char *line;

///Количество хранимых байтов в строке line. size_t line_len;

/** Указатель функции на пользовательскую функцию чтения для интерфейса pop3_str_getdelimfd. Этот прототип функции имеет семантику, аналогичную функции чтения.

Параметр @p gdfd позволяет настраиваемой функции извлекать информацию user_data

из структуры str_getdelimfd, которая может содержать указатель файла, соединение сокета...

*/

long (*getdelimfd_read)(struct str_getdelimfd *const gdfd, void *buf, size_t count);

///Пользовательские данные, которые отправляются в функцию-обработчик чтения.

void *user_data;

///Разделитель символов. int delim;

///Заполнение для выравнивания. char pad[4];

};

/// Данные заголовка письма. struct pop3_header

{

///Имя заголовка (список заголовков сортируется по имени заголовка). char *key;

///Содержимое соответствующего ключа заголовка.

char *value;

};

/// Основная структура данных, которая содержит контекст клиента POP3. struct pop3

{

///Побитовый список флагов, управляющих поведением POP3-клиента. enum pop3_flag flags;

///Описатель сокета.

int sock;

///Буфер чтения и структура синтаксического анализа строк. struct str_getdelimfd gdfd;

///Список писем.

struct pop3_message *messages;

///Количество писем в списке писем. size_t messages_count;

/** Тайм-аут в секундах для ожидания перед возвратом с ошибкой.

* Это относится как к записи, так и к чтению из сетевого сокета. */ long timeout_sec;

///Код состояния, указывающий на успех / неудачу.

enum pop3_status_code status_code;

/** Указывает, есть ли в этом контексте активное соединение TLS.

*0 означает, что TLS-соединение неактивно.

*1 означает, что TLS-соединение активно. */ int tls_on;

/** Путь к файлу сертификата при использовании самозаверяющего или ненадежного сертификата,

*не находящегося в хранилище сертификатов по умолчанию. */

const char *cafile;

/// Описание последней ошибки char *error_description;

#ifdef POP3_OPENSSL

///OpenSSL TLS объект. SSL *tls;

///OpenSSL TLS контекст. SSL_CTX *tls_ctx;

///OpenSSL TLS I/O абстракция. BIO *tls_bio;

#endif // POP3_OPENSSL };

/** Проверяет,

приведет ли

сложение значений size_t к переносу.

* @param[in]

a

Складывает это

значение

с

@p

b .

* @param[in]

b

Складывает это

значение

с

@p

a .

* @param[out]

result

Сохраняет результат сложения

в этот буфер.

*

 

Если

установлено значение

NULL, результат не записывается.

*@retval 1 Перенос совершен.

*@retval 0 Перенос не совершен. */

static int pop3_si_add_size_t(const size_t a, const size_t b, size_t *const result)

{

int wraps = (int)(SIZE_MAX - a < b); if (result)

*result = a + b; return wraps;

}

/** Проверяет, приведет ли вычитание значений size_t к заему. * @param[in] a Вычитает из этого значения @p b .

* @param[in] b Вычитает это значение из @p a .

17

pop3_lib/pop3_lib.c

*

@param[out] result Сохраняет результат вычитания в

этот буфер.

*

Если установлено значение NULL,

результат не записывается.

*@retval 1 Заем совершен.

*@retval 0 Заем не совершен. */

static int pop3_si_sub_size_t(const size_t a, const size_t b, size_t *const result)

{

int wraps = (int)(a < b); if (result)

*result = a - b; return wraps;

}

/** Ожидает, пока на стороне чтения сокета не станет доступно больше данных.

*@param[in] pop3 Контекст клиента POP3.

*@retval POP3_STATUS_OK Если данные доступны для чтения на сокете.

*@retval POP3_STATUS_RECV Если соединение прерывается до того,

* как в сокете появятся какие-либо данные. */

static enum pop3_status_code pop3_str_getdelimfd_read_timeout(struct pop3 *const pop3)

{

fd_set readfds;

struct timeval timeout; FD_ZERO(&readfds); FD_SET(pop3->sock, &readfds); timeout.tv_sec = pop3->timeout_sec; timeout.tv_usec = 0;

if (select(pop3->sock + 1, &readfds, NULL, NULL, &timeout) < 1) return pop3_status_code_set(pop3, POP3_STATUS_RECV);

return pop3->status_code = POP3_STATUS_OK;

}

/** Эта функция вызывается интерфейсом pop3_str_getdelimfd, когда ему нужно прочитать больше данных.

*Читает, используя либо простое соединение сокета, если шифрование не включено,

*либо читает, используя OpenSSL, если у него есть активное соединение TLS.

* @param[in]

gdfd

См. @ref str_getdelimfd.

*

@param[out]

buf

Указатель на

буфер для хранения прочитанных байтов.

*

@param[in]

count

Максимальное

количество байтов для чтения.

*@retval >=0 Количество прочитанных байтов.

*@retval -1 Не удалось прочитать из сокета. */

static long pop3_str_getdelimfd_read(struct str_getdelimfd *const gdfd, void *buf, size_t count)

{

struct pop3 *pop3; long bytes_read = 0; pop3 = gdfd->user_data;

if (pop3_str_getdelimfd_read_timeout(pop3) != POP3_STATUS_OK) return -1;

if (pop3->tls_on)

{

#ifdef POP3_OPENSSL do

{

/* Count никогда не будет иметь значение больше POP3_GETDELIM_READ_SZ, поэтому мы можем безопасно преобразовать его в int. */

bytes_read = SSL_read(pop3->tls, buf, (int)count);

} while (bytes_read <= 0 && BIO_should_retry(pop3->tls_bio)); #endif // POP3_OPENSSL

}

else

bytes_read = recv(pop3->sock, buf, count, 0); return bytes_read;

}

/** Возвращает

расположение символа-разделителя в буфере поиска.

* @param[in]

buf

Буфер поиска, используемый для

поиска разделителя.

* @param[in]

buf_len

Количество байтов для поиска в

buf.

* @param[in]

delim

Разделитель для поиска в buf.

 

* @param[out]

delim_pos

Если разделитель найден в buf,

возвращает позицию разделителя

*

 

в этом параметре, в противном случае 0.

*

 

Этот аргумент не должен быть равен NULL.

*@retval 1 Если символ-разделитель найден.

*@retval 0 Если символ-разделитель не найден. */

static int pop3_str_getdelimfd_search_delim(const char *const buf, size_t buf_len, int delim, size_t *const delim_pos)

{

*delim_pos = 0;

for (size_t i = 0; i < buf_len; ++i) if (buf[i] == delim)

{

*delim_pos = i; return 1;

}

return 0;

}

/** Инициализирует внутренний строчный буфер.

* @param[in] gdfd См. @ref str_getdelimfd.

18

pop3_lib/pop3_lib.c

* @param[in] copy_len Количество байтов для копирования во внутренний строчный буфер. * @retval 0 Данные успешно размещены и скопированы в буфер новой строки.

* @retval -1 Не удалось выделить память для буфера новой строки. */

static int pop3_str_getdelimfd_set_line_and_buf(struct str_getdelimfd *const gdfd, size_t copy_len)

{

size_t copy_len_inc, nbytes_to_shift, new_buf_len; if (gdfd->line)

{

free(gdfd->line); gdfd->line = NULL;

}

if (pop3_si_add_size_t(copy_len, 2, &copy_len_inc) || pop3_si_add_size_t((size_t)gdfd->_buf, copy_len_inc - 1, NULL) || pop3_si_sub_size_t(gdfd->_buf_len, copy_len, &nbytes_to_shift) || (gdfd->line = malloc(copy_len_inc)) == NULL)

return -1;

memcpy(gdfd->line, gdfd->_buf, copy_len_inc); gdfd->line_len = copy_len_inc;

memmove(gdfd->_buf, gdfd->_buf + (copy_len_inc - 1), nbytes_to_shift); if (pop3_si_sub_size_t(nbytes_to_shift, 1, &new_buf_len) == 0)

gdfd->_buf_len = new_buf_len; return 0;

}

/** Освобождает память @p gdfd .

* @param[in] gdfd См. @ref str_getdelimfd. */

static void pop3_str_getdelimfd_free(struct str_getdelimfd *const gdfd)

{

free(gdfd->_buf); free(gdfd->line); gdfd->_buf = NULL; gdfd->_bufsz = 0; gdfd->_buf_len = 0; gdfd->line = NULL; gdfd->line_len = 0;

}

/** Освобождает память @p gdfd и возвращает код ошибки @ref STRING_GETDELIMFD_ERROR .

*@param[in] gdfd См. @ref str_getdelimfd.

*@return См. @ref str_getdelim_retcode. */

static enum str_getdelim_retcode pop3_str_getdelimfd_throw_error(struct str_getdelimfd *const gdfd)

{

pop3_str_getdelimfd_free(gdfd); return STRING_GETDELIMFD_ERROR;

}

/** Величина, на которую увеличивается буфер чтения, если разделитель не найден. */

#define POP3_GETDELIM_READ_SZ 1000

/** Читает и анализирует строку с разделителями, используя настраиваемую функцию чтения.

*Этот интерфейс обрабатывает всю логику для расширения буфера, анализа разделителя в буфере и

*возврата каждой "строки" вызывающей стороне для обработки.

*@param[in] gdfd См. @ref str_getdelimfd.

*@return См. @ref str_getdelim_retcode. */

static enum str_getdelim_retcode pop3_str_getdelimfd(struct str_getdelimfd *const gdfd)

{

size_t delim_pos, buf_sz_remaining, buf_sz_new; long bytes_read = -1;

void *read_buf_ptr; char *buf_new;

if (gdfd->getdelimfd_read == NULL) return STRING_GETDELIMFD_ERROR;

while (1)

{

if (pop3_str_getdelimfd_search_delim(gdfd->_buf, gdfd->_buf_len, gdfd->delim, &delim_pos))

{

if (pop3_str_getdelimfd_set_line_and_buf(gdfd, delim_pos) < 0) return pop3_str_getdelimfd_throw_error(gdfd);

return STRING_GETDELIMFD_DONE;

}

else if (bytes_read == 0)

{

if (pop3_str_getdelimfd_set_line_and_buf(gdfd, gdfd->_buf_len) < 0) return pop3_str_getdelimfd_throw_error(gdfd);

return STRING_GETDELIMFD_DONE;

}

if (pop3_si_sub_size_t(gdfd->_bufsz, gdfd->_buf_len, &buf_sz_remaining)) return pop3_str_getdelimfd_throw_error(gdfd);

if (buf_sz_remaining < POP3_GETDELIM_READ_SZ)

{

if (pop3_si_add_size_t(buf_sz_remaining, POP3_GETDELIM_READ_SZ, &buf_sz_new)) return pop3_str_getdelimfd_throw_error(gdfd);

buf_new = realloc(gdfd->_buf, buf_sz_new); if (buf_new == NULL)

return pop3_str_getdelimfd_throw_error(gdfd);

19

pop3_lib/pop3_lib.c

gdfd->_buf = buf_new; gdfd->_bufsz = buf_sz_new;

}

if (pop3_si_add_size_t((size_t)gdfd->_buf, gdfd->_buf_len, NULL)) return pop3_str_getdelimfd_throw_error(gdfd);

read_buf_ptr = gdfd->_buf + gdfd->_buf_len;

bytes_read = (*gdfd->getdelimfd_read)(gdfd, read_buf_ptr, POP3_GETDELIM_READ_SZ); if (bytes_read < 0 ||

pop3_si_add_size_t(gdfd->_buf_len, (size_t)bytes_read, &gdfd->_buf_len)) return pop3_str_getdelimfd_throw_error(gdfd);

}

}

/** Копирует строку @p s2 в @p s1 .

*Эта функция ведет себя почти аналогично функции strcpy(), но

*возвращает указатель на конец скопированного буфера в целевой строке.

*Эта функция всегда добавляет '\0' в конец строки.

*@param[in] s1 Целевая строка.

*@param[in] s2 Строка с завершающим нулем для копирования в @p s1 .

*@return Указатель на место в @p s1 после последнего скопированного байта. */ static char *pop3_stpcpy(char *s1, const char *s2)

{

size_t i = 0; do

{

s1[i] = s2[i];

} while (s2[i++] != '\0'); return &s1[i - 1];

}

/** Копирует строку в новый динамически выделяемый буфер.

*Возвращает динамически выделяемую строку с тем же содержимым, что и входная строка.

*По завершении вызывающая сторона должна освободить возвращенную строку.

*@param[in] s Строка для дублирования.

* @param[in] max_chars Максимальное число символов.

*@retval char* Указатель на новую динамически выделяемую строку, дублированную из @p s .

*@retval NULL Не удалось выделить память для новой строки. */

static char *pop3_strdup(const char *s, size_t max_chars)

{

if (s != NULL)

{

char *dup;

size_t dup_len, slen = max_chars ? max_chars : strlen(s); if (pop3_si_add_size_t(slen, 1, &dup_len))

dup = NULL, errno = ENOMEM;

else if ((dup = malloc(dup_len)) != NULL)

{

memcpy(dup, s, slen); dup[slen] = '\0';

}

return dup;

}

return NULL;

}

/** Таблица поиска, используемая для декодирования данных base64.

*Для кодирования base64 каждые шесть битов были закодированы с использованием только символов

*ASCII из g_base64_encode_table. В этой таблице записи позволяют отменить

*этот процесс. Таблица имеет 128 записей, которые соответствуют значению индекса из таблицы

*кодирования.

*Если результат индексации заканчивается на -1 во время процесса декодирования, это

*указывает на недопустимый символ base64 в закодированных данных. */

static signed char g_base64_decode_table[] = {

-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, // +

-1, -1, -1, 63,

 

 

// /

52, 53, 54, 55, 56, 57, 58, 59,

60,

61,

// 0 - 9

-1, -1, -1, -1, -1, -1, -1, 0,

1,

2, 3, 4, 5, 6, 7, 8, 9,

// A - J

10, 11, 12, 13, 14, 15, 16, 17,

18,

19,

// K - T

20, 21, 22, 23, 24, 25,

 

 

// U - Z

-1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,

// a - j

36, 37, 38, 39, 40, 41, 42, 43,

44,

45,

// k - t

46, 47, 48, 49, 50, 51,

 

 

// u - z

-1, -1, -1, -1, -1};

 

 

 

/** Декодирует строку base64 в двоичные данные.

*Параметр декодирования будет динамически выделен этой функцией, если она успешно завершится.

*Следовательно, вызывающая сторона должна освободить параметр декодирования после использования.

* @param[in]

buf

Строка base64 с '\0'.

* @param[out]

decode Указатель на буфер,

который будет выделяться динамически и будет содержать

*

 

декодированные двоичные данные.

*

 

Этот параметр будет

установлен в NULL, если не удалось выделить память.

*@retval >=0 Длина данных, хранящихся в параметре декодирования.

*@retval -1 Ошибка выделения памяти или недопустимые байтовые последовательности base64. */ static size_t pop3_base64_decode(const char *const buf, unsigned char **decode)

20