Probe external accounts through libcurl
This commit is contained in:
@@ -41,6 +41,64 @@
|
||||
|
||||
CollectorGlobals Collector = {0};
|
||||
|
||||
static size_t DiscardCurlData(char *ptr, size_t size, size_t count, void *data)
|
||||
{
|
||||
(void) ptr; (void) data;
|
||||
return size * count;
|
||||
}
|
||||
|
||||
static int ProbeExternalAccount(sqlite3 *database,
|
||||
const CollectorExternalAccount *account,
|
||||
long now)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
char secret[512];
|
||||
char url[768];
|
||||
char error[CURL_ERROR_SIZE] = {0};
|
||||
const char *scheme;
|
||||
CURLcode code;
|
||||
int secretResult;
|
||||
|
||||
if (account->inbound_protocol[0] == '\0' || account->inbound_host[0] == '\0' ||
|
||||
account->inbound_secret_id[0] == '\0') {
|
||||
CollectorAccountsMarkResult(database, account->id, now, 0,
|
||||
"external account is missing transport credentials");
|
||||
return -1;
|
||||
}
|
||||
secretResult = CollectorAccountsSecretGet(database, account->inbound_secret_id,
|
||||
secret, sizeof(secret));
|
||||
if (secretResult != 1) {
|
||||
CollectorAccountsMarkResult(database, account->id, now, 0,
|
||||
"external account secret not found or too long");
|
||||
return -1;
|
||||
}
|
||||
scheme = strcmp(account->inbound_protocol, "imap") == 0 ? "imap" : "pop3";
|
||||
if (snprintf(url, sizeof(url), "%s%s://%s:%d/%s", scheme,
|
||||
strcmp(account->inbound_tls, "implicit") == 0 ? "s" : "",
|
||||
account->inbound_host, account->inbound_port,
|
||||
account->destination_folder[0] != '\0' ? account->destination_folder : "INBOX") >= (int) sizeof(url)) {
|
||||
CollectorAccountsMarkResult(database, account->id, now, 0, "external account URL too long");
|
||||
return -1;
|
||||
}
|
||||
curl = curl_easy_init();
|
||||
if (curl == NULL) return -1;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, account->inbound_username);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, secret);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DiscardCurlData);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
|
||||
code = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (code != CURLE_OK) {
|
||||
CollectorAccountsMarkResult(database, account->id, now, 0,
|
||||
error[0] != '\0' ? error : curl_easy_strerror(code));
|
||||
return -1;
|
||||
}
|
||||
return CollectorAccountsMarkResult(database, account->id, now, 1, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
CollectorLoop(void *ignored)
|
||||
{
|
||||
@@ -61,6 +119,10 @@ CollectorLoop(void *ignored)
|
||||
Log(LOG_ERROR, "Unable to query due external mail accounts");
|
||||
} else if (due > 0) {
|
||||
Log(LOG_DEBUG, "%d external mail account(s) are due for collection", due);
|
||||
CollectorExternalAccount account;
|
||||
if (CollectorAccountsNextDue(accounts, (long) now, &account) == 1) {
|
||||
ProbeExternalAccount(accounts, &account, (long) now);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastCalendarCollection == 0 || now - lastCalendarCollection >= 6 * 60 * 60) {
|
||||
|
||||
@@ -82,7 +82,7 @@ CollectorAccountsNextDue(sqlite3 *database, long now,
|
||||
sqlite3_stmt *statement = NULL;
|
||||
const char query[] =
|
||||
"SELECT id, owner, email_address, inbound_protocol, inbound_host, "
|
||||
"inbound_port, inbound_tls, inbound_username, destination_folder, "
|
||||
"inbound_port, inbound_tls, inbound_username, inbound_secret_id, destination_folder, "
|
||||
"delete_policy, COALESCE(delete_after_days, 0) "
|
||||
"FROM external_accounts WHERE enabled = 1 AND inbound_protocol != 'none' "
|
||||
"AND (last_checked_at IS NULL OR last_checked_at + poll_interval <= ?) "
|
||||
@@ -116,9 +116,10 @@ CollectorAccountsNextDue(sqlite3 *database, long now,
|
||||
account->inbound_port = sqlite3_column_int(statement, 5);
|
||||
COPY_ACCOUNT_FIELD(6, inbound_tls);
|
||||
COPY_ACCOUNT_FIELD(7, inbound_username);
|
||||
COPY_ACCOUNT_FIELD(8, destination_folder);
|
||||
COPY_ACCOUNT_FIELD(9, delete_policy);
|
||||
account->delete_after_days = sqlite3_column_int(statement, 10);
|
||||
COPY_ACCOUNT_FIELD(8, inbound_secret_id);
|
||||
COPY_ACCOUNT_FIELD(9, destination_folder);
|
||||
COPY_ACCOUNT_FIELD(10, delete_policy);
|
||||
account->delete_after_days = sqlite3_column_int(statement, 11);
|
||||
#undef COPY_ACCOUNT_FIELD
|
||||
sqlite3_finalize(statement);
|
||||
return 1;
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef struct {
|
||||
int inbound_port;
|
||||
char inbound_tls[16];
|
||||
char inbound_username[256];
|
||||
char inbound_secret_id[128];
|
||||
char destination_folder[256];
|
||||
char delete_policy[16];
|
||||
int delete_after_days;
|
||||
|
||||
Reference in New Issue
Block a user