imap/smtp polishing;
This commit is contained in:
parent
f5a2d2b38f
commit
f42c6b1dbe
56
include/ilib/curl_imapsmtp.h
Normal file
56
include/ilib/curl_imapsmtp.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* this is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* this is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||||
|
*
|
||||||
|
* (c) Alexander Vdolainen 2007, 2026 <alex@vapaa.xyz>
|
||||||
|
* subrelay: a minimalistic maillist server based on external IMAPs/SMTPs
|
||||||
|
*
|
||||||
|
* curl_imapsmtp.h: IMAPS SMTPs functions using libcurl
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __MAIL_ENGINE_H__
|
||||||
|
#define __MAIL_ENGINE_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <ilib/configuration.h>
|
||||||
|
|
||||||
|
#define MAX_IMAP_RESPONSE (25u * 1024u * 1024u)
|
||||||
|
|
||||||
|
typedef struct mail_message {
|
||||||
|
char *raw_data; /* Full raw RFC 822 byte payload */
|
||||||
|
size_t size; /* Size of raw payload */
|
||||||
|
unsigned long uid; /* IMAP Unique Identifier */
|
||||||
|
} mail_message_t;
|
||||||
|
|
||||||
|
typedef struct mail_list_results {
|
||||||
|
unsigned long *uids;
|
||||||
|
size_t count;
|
||||||
|
} mail_list_results_t;
|
||||||
|
|
||||||
|
/* Initialize and cleanup global libcurl environment */
|
||||||
|
int mail_engine_global_init(void);
|
||||||
|
void mail_engine_global_cleanup(void);
|
||||||
|
|
||||||
|
/* IMAP Client API */
|
||||||
|
int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *results);
|
||||||
|
int imap_fetch_message(const subrelay_config_t *cfg, unsigned long uid, mail_message_t *msg);
|
||||||
|
int imap_expunge_message(const subrelay_config_t *cfg, unsigned long uid);
|
||||||
|
void mail_message_free(mail_message_t *msg);
|
||||||
|
void mail_list_results_free(mail_list_results_t *res);
|
||||||
|
|
||||||
|
/* SMTP Client API */
|
||||||
|
int smtp_send_message(const subrelay_config_t *cfg, const char **recipients,
|
||||||
|
size_t recipient_count, const char *raw_msg, size_t msg_len);
|
||||||
|
|
||||||
|
#endif /* __MAIL_ENGINE_H__ */
|
||||||
@ -1,38 +0,0 @@
|
|||||||
/* mail_engine.h - IMAP fetching & SMTP fan-out engine using libcurl */
|
|
||||||
#ifndef __MAIL_ENGINE_H__
|
|
||||||
#define __MAIL_ENGINE_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include <ilib/configuration.h>
|
|
||||||
|
|
||||||
typedef struct mail_message {
|
|
||||||
char *raw_data; /* Full raw RFC 822 byte payload */
|
|
||||||
size_t size; /* Size of raw payload */
|
|
||||||
unsigned long uid; /* IMAP Unique Identifier */
|
|
||||||
} mail_message_t;
|
|
||||||
|
|
||||||
typedef struct mail_list_results {
|
|
||||||
unsigned long *uids;
|
|
||||||
size_t count;
|
|
||||||
} mail_list_results_t;
|
|
||||||
|
|
||||||
/* Initialize and cleanup global libcurl environment */
|
|
||||||
int mail_engine_global_init(void);
|
|
||||||
void mail_engine_global_cleanup(void);
|
|
||||||
|
|
||||||
/* IMAP Client API */
|
|
||||||
int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *results);
|
|
||||||
int imap_fetch_message(const subrelay_config_t *cfg, unsigned long uid, mail_message_t *msg);
|
|
||||||
int imap_expunge_message(const subrelay_config_t *cfg, unsigned long uid);
|
|
||||||
void mail_message_free(mail_message_t *msg);
|
|
||||||
void mail_list_results_free(mail_list_results_t *res);
|
|
||||||
|
|
||||||
/* SMTP Client API */
|
|
||||||
int smtp_send_message(const subrelay_config_t *cfg,
|
|
||||||
const char **recipients,
|
|
||||||
size_t recipient_count,
|
|
||||||
const char *raw_msg,
|
|
||||||
size_t msg_len);
|
|
||||||
|
|
||||||
#endif /* __MAIL_ENGINE_H__ */
|
|
||||||
@ -24,7 +24,7 @@
|
|||||||
#include <ilib/configuration.h>
|
#include <ilib/configuration.h>
|
||||||
#include <ilib/subscribers.h>
|
#include <ilib/subscribers.h>
|
||||||
#include <ilib/pending.h>
|
#include <ilib/pending.h>
|
||||||
#include <ilib/mail_engine.h>
|
#include <ilib/curl_imapsmtp.h>
|
||||||
|
|
||||||
typedef struct mail_processor {
|
typedef struct mail_processor {
|
||||||
subrelay_config_t *cfg;
|
subrelay_config_t *cfg;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ bin_PROGRAMS = subrelayd sbrlctrl
|
|||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
$(top_srcdir)/include/ilib/configuration.h \
|
$(top_srcdir)/include/ilib/configuration.h \
|
||||||
$(top_srcdir)/include/ilib/local.h \
|
$(top_srcdir)/include/ilib/local.h \
|
||||||
$(top_srcdir)/include/ilib/mail_engine.h \
|
$(top_srcdir)/include/ilib/curl_imapsmtp.h \
|
||||||
$(top_srcdir)/include/ilib/mail_processor.h \
|
$(top_srcdir)/include/ilib/mail_processor.h \
|
||||||
$(top_srcdir)/include/ilib/pending.h \
|
$(top_srcdir)/include/ilib/pending.h \
|
||||||
$(top_srcdir)/include/ilib/splay.h \
|
$(top_srcdir)/include/ilib/splay.h \
|
||||||
@ -20,7 +20,7 @@ subrelayd_SOURCES = \
|
|||||||
pending.c \
|
pending.c \
|
||||||
configuration.c \
|
configuration.c \
|
||||||
template.c \
|
template.c \
|
||||||
mail_engine.c \
|
curl_imapsmtp.c \
|
||||||
mail_processor.c \
|
mail_processor.c \
|
||||||
local.c
|
local.c
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,33 @@
|
|||||||
/* mail_engine.c - libcurl IMAP and SMTP implementation */
|
/*
|
||||||
|
* this is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* this is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||||
|
*
|
||||||
|
* (c) Alexander Vdolainen 2007, 2026 <alex@vapaa.xyz>
|
||||||
|
* subrelay: a minimalistic maillist server based on external IMAPs/SMTPs
|
||||||
|
*
|
||||||
|
* curl_imapsmtp.c: IMAPS SMTPs functions using libcurl
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include <ilib/mail_engine.h>
|
#include <ilib/curl_imapsmtp.h>
|
||||||
|
|
||||||
typedef struct memory_buffer {
|
typedef struct memory_buffer {
|
||||||
char *data;
|
char *data;
|
||||||
@ -20,24 +42,28 @@ typedef struct upload_buffer {
|
|||||||
/* Callback for libcurl to append fetched HTTP/IMAP bytes into memory */
|
/* Callback for libcurl to append fetched HTTP/IMAP bytes into memory */
|
||||||
static size_t write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp)
|
static size_t write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||||
{
|
{
|
||||||
size_t real_size = size * nmemb;
|
memory_buffer_t *mem = userp;
|
||||||
memory_buffer_t *mem = (memory_buffer_t *)userp;
|
|
||||||
|
|
||||||
char *ptr = realloc(mem->data, mem->size + real_size + 1);
|
if (size != 0 && nmemb > SIZE_MAX / size) return 0;
|
||||||
if (!ptr) return 0; /* Out of memory */
|
size_t n = size * nmemb;
|
||||||
|
if (n > MAX_IMAP_RESPONSE - mem->size) return 0;
|
||||||
|
|
||||||
|
char *ptr = realloc(mem->data, mem->size + n + 1);
|
||||||
|
if (!ptr) return 0;
|
||||||
|
|
||||||
mem->data = ptr;
|
mem->data = ptr;
|
||||||
memcpy(&(mem->data[mem->size]), contents, real_size);
|
memcpy(mem->data + mem->size, contents, n);
|
||||||
mem->size += real_size;
|
mem->size += n;
|
||||||
mem->data[mem->size] = 0;
|
mem->data[mem->size] = '\0';
|
||||||
|
|
||||||
return real_size;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for libcurl to read bytes when sending outbound mail via SMTP */
|
/* Callback for libcurl to read bytes when sending outbound mail via SMTP */
|
||||||
static size_t read_payload_callback(char *buffer, size_t size, size_t nitems, void *userp)
|
static size_t read_payload_callback(char *buffer, size_t size, size_t nitems, void *userp)
|
||||||
{
|
{
|
||||||
upload_buffer_t *upload = (upload_buffer_t *)userp;
|
upload_buffer_t *upload = (upload_buffer_t *)userp;
|
||||||
|
if (size != 0 && nitems > SIZE_MAX / size) return CURL_READFUNC_ABORT;
|
||||||
size_t max_bytes = size * nitems;
|
size_t max_bytes = size * nitems;
|
||||||
|
|
||||||
if (upload->bytes_remaining == 0) return 0; /* EOF */
|
if (upload->bytes_remaining == 0) return 0; /* EOF */
|
||||||
@ -61,9 +87,7 @@ void mail_engine_global_cleanup(void)
|
|||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* IMAPs */
|
||||||
/* IMAP Operations */
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *results)
|
int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *results)
|
||||||
{
|
{
|
||||||
@ -77,6 +101,7 @@ int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *re
|
|||||||
snprintf(url, sizeof(url), "imaps://%s:%d/INBOX", cfg->imap_host, cfg->imap_port);
|
snprintf(url, sizeof(url), "imaps://%s:%d/INBOX", cfg->imap_host, cfg->imap_port);
|
||||||
|
|
||||||
memory_buffer_t buf = { calloc(1, 1), 0 };
|
memory_buffer_t buf = { calloc(1, 1), 0 };
|
||||||
|
if(!buf.data) return -ENOMEM;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(curl, CURLOPT_USERNAME, cfg->maillist_addr);
|
curl_easy_setopt(curl, CURLOPT_USERNAME, cfg->maillist_addr);
|
||||||
@ -97,12 +122,18 @@ int imap_fetch_unseen_uids(const subrelay_config_t *cfg, mail_list_results_t *re
|
|||||||
/* Parse IMAP response string (e.g., "* SEARCH 101 102 103\r\n") */
|
/* Parse IMAP response string (e.g., "* SEARCH 101 102 103\r\n") */
|
||||||
char *search_str = strstr(buf.data, "* SEARCH");
|
char *search_str = strstr(buf.data, "* SEARCH");
|
||||||
if (search_str) {
|
if (search_str) {
|
||||||
search_str += 8; /* Skip "* SEARCH" */
|
search_str += 8; /* skip "* SEARCH" */
|
||||||
char *token = strtok(search_str, " \r\n");
|
char *token = strtok(search_str, " \r\n");
|
||||||
while (token) {
|
while (token) {
|
||||||
unsigned long uid = strtoul(token, NULL, 10);
|
unsigned long uid = strtoul(token, NULL, 10);
|
||||||
if (uid > 0) {
|
if (uid > 0) {
|
||||||
results->uids = realloc(results->uids, sizeof(unsigned long) * (results->count + 1));
|
unsigned long *tmp = realloc(results->uids, sizeof(unsigned long) * (results->count + 1));
|
||||||
|
if(!tmp) {
|
||||||
|
free(buf.data);
|
||||||
|
mail_list_results_free(results);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
results->uids = tmp;
|
||||||
results->uids[results->count++] = uid;
|
results->uids[results->count++] = uid;
|
||||||
}
|
}
|
||||||
token = strtok(NULL, " \r\n");
|
token = strtok(NULL, " \r\n");
|
||||||
@ -125,6 +156,7 @@ int imap_fetch_message(const subrelay_config_t *cfg, unsigned long uid, mail_mes
|
|||||||
snprintf(url, sizeof(url), "imaps://%s:%d/INBOX;UID=%lu", cfg->imap_host, cfg->imap_port, uid);
|
snprintf(url, sizeof(url), "imaps://%s:%d/INBOX;UID=%lu", cfg->imap_host, cfg->imap_port, uid);
|
||||||
|
|
||||||
memory_buffer_t buf = { calloc(1, 1), 0 };
|
memory_buffer_t buf = { calloc(1, 1), 0 };
|
||||||
|
if(!buf.data) return -ENOMEM;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(curl, CURLOPT_USERNAME, cfg->maillist_addr);
|
curl_easy_setopt(curl, CURLOPT_USERNAME, cfg->maillist_addr);
|
||||||
@ -179,15 +211,10 @@ int imap_expunge_message(const subrelay_config_t *cfg, unsigned long uid)
|
|||||||
return (res == CURLE_OK) ? 0 : -EIO;
|
return (res == CURLE_OK) ? 0 : -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* SMTPS */
|
||||||
/* SMTP Operations */
|
|
||||||
/* -------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
int smtp_send_message(const subrelay_config_t *cfg,
|
int smtp_send_message(const subrelay_config_t *cfg, const char **recipients, size_t recipient_count,
|
||||||
const char **recipients,
|
const char *raw_msg, size_t msg_len)
|
||||||
size_t recipient_count,
|
|
||||||
const char *raw_msg,
|
|
||||||
size_t msg_len)
|
|
||||||
{
|
{
|
||||||
if (!cfg || !recipients || recipient_count == 0 || !raw_msg) return -EINVAL;
|
if (!cfg || !recipients || recipient_count == 0 || !raw_msg) return -EINVAL;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@
|
|||||||
#include <ilib/configuration.h>
|
#include <ilib/configuration.h>
|
||||||
#include <ilib/subscribers.h>
|
#include <ilib/subscribers.h>
|
||||||
#include <ilib/pending.h>
|
#include <ilib/pending.h>
|
||||||
#include <ilib/mail_engine.h>
|
#include <ilib/curl_imapsmtp.h>
|
||||||
#include <ilib/mail_processor.h>
|
#include <ilib/mail_processor.h>
|
||||||
#include <ilib/local.h>
|
#include <ilib/local.h>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user