Files
smmapdfw/smmapdfw/cyrus_worker/cyrus_worker.c
2004-10-14 09:07:22 +00:00

261 lines
6.4 KiB
C

/*
Copyright (C) 2004, Wolfgang Hottgenroth
This file is part of smmapdfw.
smmapdfw 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.
smmapdfw 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 smmapdfw. If not, write to the Free Software Foundation, 59
Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include "containers_public.h"
#include "smmapd.h"
#include "smtp.h"
#include "htdns.h"
#define SMM_LOCAL_PERM_NOK 101
#define SMM_LOCAL_TEMP_NOK 102
#define SMM_LOCAL_OK 103
struct cyrus_container_handle_s {
cfgl_t *cfg;
int timeout;
char *sender_address;
char *lhlo_arg;
int lmtp_port;
};
typedef struct cyrus_container_handle_s cyrus_container_handle_t;
struct cyrus_work_handle_s {
int id;
cyrus_container_handle_t *cch;
};
typedef struct cyrus_work_handle_s cyrus_work_handle_t;
int cyrus_init(cfgl_t *cfg, void **handle);
int cyrus_destroy(void *handle);
/* int cyrus_work_setup(void *handle, void **work_handle); */
int cyrus_work(void *handle, void *work_handle, char *input, char *output);
/* int cyrus_work_destroy(void *handle, void *work_handle); */
class_descriptor_t cyruscheck = {
"cyruscheck",
&cyrus_init,
&cyrus_destroy,
NULL, /* &cyrus_work_setup, */
&cyrus_work,
NULL /* &cyrus_work_destroy */
};
int cyrus_init(cfgl_t *cfg, void **handle) {
cyrus_container_handle_t *cch;
cch = (cyrus_container_handle_t*) malloc(sizeof(cyrus_container_handle_t));
cch->cfg = cfg;
cch->timeout = atoi(findcfglx(cch->cfg, "timeout", "5"));
cch->sender_address = findcfglx(cch->cfg, "sender_address", "<>");
cch->lhlo_arg = findcfglx(cch->cfg, "lhlo_arg", "local");
cch->lmtp_port = atoi(findcfglx(cch->cfg, "lmtp_port", "24"));
*handle = cch;
return 0;
}
int cyrus_destroy(void *handle) {
cyrus_container_handle_t *cch = (cyrus_container_handle_t*)handle;
free(cch);
return 0;
}
int cyrus_work(void *handle, void *work_handle, char *input, char *output) {
static const char *DEFAULT_ANSWER = "default answer";
static const char *ILLEGAL_INPUT = "illegal input (must be 'depot_uid depot_host')";
static const char *UNEXPECTED_ERROR = "unexpected error in lmtp dialog";
static const char *TIMEOUT_ERROR = "timeout on lmtp dialog";
static const char *GO_AHEAD = "go ahead";
static const char *DEPOT_DNS_ERROR = "depot could not be found in dns";
static int log_id = 0;
cyrus_container_handle_t *cch = (cyrus_container_handle_t*) handle;
int result = SMM_TEMP_NOK;
char *depot_uid, *depot_host, *response_text, *tmp_arg;
smtp_t *lmtp;
a_rdata_t **a_rdata;
int ip_address, done=0, err;
enum {
CONNECT, LHLO, MAILFROM, RCPTTO, RSET, QUIT, END
} state = CONNECT;
log_id++;
syslog(LOG_DEBUG, "cyrus_work: (%04x) going to check %s", log_id, input);
depot_uid = input;
if (NULL == (depot_host = strchr(depot_uid, ' '))) {
snprintf(output, ANSWER_BUFSIZE, ILLEGAL_INPUT);
return SMM_PERM_NOK;
}
*depot_host = '\0';
depot_host++;
a_rdata = get_a_rrs(depot_host);
if (NULL == a_rdata) {
syslog(LOG_DEBUG, "cyrus_work: (%04x) depot_host %s could not be found in dns",
log_id, depot_host);
snprintf(output, ANSWER_BUFSIZE, DEPOT_DNS_ERROR);
return SMM_TEMP_NOK;
}
ip_address = (*a_rdata)->address;
free_rrs((void**)a_rdata);
syslog(LOG_DEBUG, "cyrus_work: (%04x) depot_uid %s, depot_host %s", log_id,
depot_uid, depot_host);
lmtp = smtp_init(ip_address, cch->lmtp_port, cch->timeout);
while ((END != state) && (0 == done)) {
syslog(LOG_DEBUG, "cyrus_work: (%04x) lmtp dialog state %d", log_id, state);
switch(state) {
case CONNECT:
err = smtp_connect(lmtp);
break;
case LHLO:
err = smtp_lhlo(lmtp, cch->lhlo_arg);
break;
case MAILFROM:
err = smtp_mailfrom(lmtp, cch->sender_address);
break;
case RCPTTO:
tmp_arg = (char*) malloc(sizeof(char) * (strlen(depot_uid)+5));
*tmp_arg = '\0';
strcat(tmp_arg, "<");
strcat(tmp_arg, depot_uid);
strcat(tmp_arg, ">");
err = smtp_rcptto(lmtp, tmp_arg);
free(tmp_arg);
break;
case RSET:
err = smtp_rset(lmtp);
break;
case QUIT:
err = smtp_quit(lmtp);
break;
}
state++;
switch(err) {
case SMTP_TIMEOUT:
syslog(LOG_DEBUG, "cyrus_work: (%04x) timeout in lmtp dialog", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)TIMEOUT_ERROR;
done = 1;
break;
case 0:
/* evaluate smtp_response, return or continue */
err = smtp_response(lmtp, &response_text);
if (-1 == err) {
syslog(LOG_DEBUG, "cyrus_work: (%04x) response could not be parsed", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)UNEXPECTED_ERROR;
done = 1;
break;
}
syslog(LOG_DEBUG, "cyrus_work: (%04x) response: %d, %s", log_id,
err, response_text);
switch(err/100) {
case 4:
result = SMM_LOCAL_TEMP_NOK;
done = 1;
break;
case 5:
result = SMM_LOCAL_PERM_NOK;
done = 1;
break;
case 2:
if (END == state) {
result = SMM_LOCAL_OK;
response_text = (char*)GO_AHEAD;
done = 1;
break;
}
}
break;
default:
syslog(LOG_DEBUG, "cyrus_work: (%04x) unexpected error in lmtp dialog", log_id);
result = SMM_LOCAL_TEMP_NOK;
response_text = (char*)UNEXPECTED_ERROR;
done = 1;
break;
}
}
smtp_close(lmtp);
switch (result) {
case SMM_LOCAL_TEMP_NOK:
snprintf(output, ANSWER_BUFSIZE, "<TNOK><%s>", response_text);
result = SMM_OK;
break;
case SMM_LOCAL_PERM_NOK:
snprintf(output, ANSWER_BUFSIZE, "<NOK><%s>", response_text);
result = SMM_OK;
break;
case SMM_LOCAL_OK:
snprintf(output, ANSWER_BUFSIZE, "<OK><%s>", response_text);
result = SMM_OK;
break;
default:
snprintf(output, ANSWER_BUFSIZE, response_text);
break;
}
smtp_destroy(lmtp);
syslog(LOG_DEBUG, "cyrus_work: (%04x) result %d, %s", log_id,
result, output);
return result;
}