#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
#include <syslog.h>
#include "pfq_backend.h"
#include "pfq_service.h"
#include "../pfqmessage.h"
#include "../config.h"
char spool_dir[BUF_SIZE];
char exim_cmd[BUF_SIZE];
char exim_conf[BUF_SIZE];
char *q_names[]={
"input"
};
int NUMMSG_THREAD;
struct pfb_conf_t pfb_conf;
#define HEADER_FROM "From: "
#define HEADER_TO "To: "
#define HEADER_SUBJECT "Subject: "
int pfb_apiversion() {
return PFQ_API_VERSION;
}
const char* pfb_id() {
return "exim";
}
const char* pfb_version() {
return "1.3";
}
struct pfb_conf_t *pfb_getconf() {
return &pfb_conf;
}
struct msg_t* msg_from_id(const char* mid) {
int i;
for ( i=0; i<NUMMSG_THREAD; i++ ) {
if ( !strncmp(ext_queue[i].id, mid, sizeof(ext_queue[i].id) ) )
return &ext_queue[i];
}
return NULL;
}
int dir_dig( const char* basedir ) {
DIR *bdir;
struct dirent *dir;
char full_path[BUF_SIZE];
struct be_msg_t *msg;
int l;
if ( NUMMSG_THREAD >= msg_max )
return -1;
if ( dig_limit && ( time(NULL)-dig_start > dig_limit ) )
return -1;
bdir = opendir ( basedir );
while ( bdir && NUMMSG_THREAD < msg_max && ( dir = readdir ( bdir ) ) ) {
if ( dig_limit && ( time(NULL)-dig_start > dig_limit ) )
return -1;
snprintf ( full_path, sizeof(full_path), "%s/%s", basedir, dir->d_name );
if ( fs_should_dig ( dir, full_path ) ) {
dir_dig ( full_path );
} else if ( NUMMSG_THREAD < msg_max && fs_should_add ( dir, full_path ) ) {
l = strlen(dir->d_name);
if ( dir->d_name[l-1]=='H' && dir->d_name[l-2]=='-') {
msg = &(my_queue[NUMMSG_THREAD]);
memcpy ( msg->id, dir->d_name, l-2 );
snprintf ( msg->path, sizeof(msg->path), "%s/%s",
basedir, dir->d_name );
msg->changed = strncmp (dir->d_name, ext_queue[NUMMSG_THREAD].id, strlen(dir->d_name)-2 );
NUMMSG_THREAD++;
}
}
}
if ( bdir )
closedir ( bdir );
return PFBE_OK;
}
int pfb_init() {
pfb_conf.max_char = 200;
strcpy ( pfb_conf.command_path, "" );
strcpy ( pfb_conf.config_path, "" );
return PFBE_OK;
}
int pfb_setup ( struct msg_t* qptr1, struct be_msg_t* qptr2 ) {
FILE *p;
char buf[BUF_SIZE];
msg_max = pfb_conf.msg_max;
dig_limit = pfb_conf.scan_limit;
ext_queue = qptr1;
my_queue = qptr2;
strcpy ( exim_cmd, "exim");
strcpy ( exim_conf, "" );
strcpy ( spool_dir, "" );
pfb_caps = BECAPS_MSG_HOLD + BECAPS_MSG_DEL + BECAPS_MSG_REQUEUE + BECAPS_MIXED_QUEUE +
BECAPS_MSG_LOG;
if ( strlen(pfb_conf.command_path ) )
snprintf ( exim_cmd, BUF_SIZE-1, "%s/exim", pfb_conf.command_path );
if ( strlen(pfb_conf.config_path) )
snprintf ( exim_conf, BUF_SIZE-1, " -C %s ", pfb_conf.config_path );
// Try exim 3...
snprintf ( buf, BUF_SIZE, "%s %s -bP spool_directory 2> /dev/null |cut -d'=' -f2|cut -c2-",
exim_cmd, exim_conf );
p = popen ( buf, "r" );
if ( p ) {
freadl ( p, spool_dir, sizeof(spool_dir) );
pclose ( p );
}
// or exim 4
if ( !strlen(spool_dir) ) {
if ( strlen(pfb_conf.command_path) )
sprintf ( exim_cmd, "%s/exim4", pfb_conf.command_path);
else
strcpy ( exim_cmd, "exim4");
snprintf ( buf, BUF_SIZE, "%s %s -bP spool_directory 2> /dev/null |cut -d'=' -f2|cut -c2-",
exim_cmd, exim_conf );
p = popen ( buf, "r" );
if ( p ) {
freadl ( p, spool_dir, sizeof(spool_dir) );
pclose ( p );
}
}
if ( !strlen(spool_dir) ) {
syslog ( LOGLEVEL, "exim pfqueue backend: cannot guess spool_directory" );
return PFBE_UNUSABLE;
}
return PFBE_OK;
}
int pfb_close() {
return PFBE_OK;
}
int pfb_fill_queue() {
char pbuf[BUF_SIZE];
NUMMSG_THREAD = 0;
snprintf ( pbuf, BUF_SIZE, "%s/input", spool_dir );
dir_dig( spool_dir );
return NUMMSG_THREAD;
}
int pfb_retr_headers( const char* msgid ) {
FILE *p;
char buf[BUF_SIZE];
int f1, f2, f3, l1, l2;
char *s1, *s2;
struct msg_t *msg;
int dirty;
msg = msg_from_id(msgid);
if ( !msg )
return PFBE_MSGNOTEX;
if ( msg->hcached )
return PFBE_MSGCACHED;
snprintf ( buf, BUF_SIZE, "%s %s -Mvh %s 2> /dev/null",
exim_cmd, exim_conf, msg->id );
p = popen ( buf, "r" );
if ( !p ) {
strcpy ( msg->from, PFBE_SERROR );
strcpy ( msg->to, PFBE_SERROR );
msg->hcached = 0;
return PFBE_MSGNOTEX;
}
f1 = f2 = f3 = 0;
dirty = 1;
strcpy ( msg->from, PFBE_SNOTFOUND );
strcpy ( msg->to, PFBE_SNOTFOUND );
l1 = strlen(HEADER_FROM);
l2 = strlen(HEADER_TO);
s1 = HEADER_FROM;
s2 = HEADER_TO;
while ( !msg->hcached && (f1==0||f2==0||f3==0) && freadl ( p, buf, BUF_SIZE ) ) {
if ( !f1 && ( !strncmp ( buf+5, s1, l1 ) ) ) {
memcpy ( msg->from, buf+l1+5, sizeof(msg->from) );
if ( !strlen(msg->from) )
strcpy ( msg->from, "Null sender" );
f1++;
}
if ( !f2 && ( !strncmp ( buf+5, s2, l2 ) ) ) {
memcpy ( msg->to, buf+l2+5, sizeof(msg->to) );
f2++;
}
if ( !f3 && !strncmp ( buf+5, HEADER_SUBJECT, strlen(HEADER_SUBJECT) ) ) {
memcpy ( msg->subj, buf+strlen(HEADER_SUBJECT)+5, sizeof(msg->subj) );
f3++;
}
}
pclose ( p );
if ( f1 && f2 && f3 )
dirty = 0;
if ( (!dirty) && strlen(msg->to) && strlen(msg->from) )
msg->hcached = 1;
else
msg->hcached = 0;
return PFBE_OK;
}
int pfb_retr_status( const char* msgid ) {
FILE *p;
char buf[BUF_SIZE];
int f1;
struct msg_t *msg;
msg = msg_from_id(msgid);
if ( !msg )
return PFBE_MSGNOTEX;
snprintf ( buf, BUF_SIZE, "%s %s -Mvh %s 2> /dev/null",
exim_cmd, exim_conf, msg->id );
p = popen ( buf, "r" );
if ( !p ) {
strcpy ( msg->stat, "cant popen" );
return PFBE_MSGNOTEX;
}
f1 = 0;
strcpy ( msg->stat, "Active" );
while ( f1==0 && freadl ( p, buf, BUF_SIZE ) ) {
if ( !strncmp ( buf, "-frozen", 7 ) )
strcpy ( msg->stat, "Frozen" );
}
pclose ( p );
msg->scached = 0;
return PFBE_OK;
}
int pfb_retr_body( const char* msgid, char *buffer, size_t buflen ) {
char b[BUF_SIZE];
int j;
FILE *p;
struct msg_t *msg;
msg = msg_from_id(msgid);
if ( !msg )
return PFBE_MSGNOTEX;
snprintf ( b, BUF_SIZE, "%s %s -Mvb %s 2> /dev/null",
exim_cmd, exim_conf, msg->id );
p = popen ( b, "r" );
if ( !p )
return PFBE_MSGNOTEX;
// Skip first line
freadl ( p, b, sizeof(b) );
j = fread( buffer, sizeof(char), buflen, p );
pclose ( p );
return j;
}
int pfb_action(int act, const char* msg) {
char b[BUF_SIZE];
char buf[BUF_SIZE];
switch ( act ) {
case MSG_DELETE:
strcpy ( b, "-Mrm" );
break;
case MSG_HOLD:
strcpy ( b, "-Mf" );
break;
case MSG_RELEASE:
strcpy ( b, "-Mt" );
break;
case MSG_REQUEUE:
strcpy ( b, "-M" );
break;
default:
return -1;
}
snprintf ( buf, BUF_SIZE, "%s %s %s %s > /dev/null",
exim_cmd, exim_conf, b, msg );
system ( buf );
return PFBE_OK;
}
int pfb_message_delete( const char* msg ) {
return pfb_action ( MSG_DELETE, msg );
}
int pfb_message_hold( const char* msg ) {
return pfb_action ( MSG_HOLD, msg );
}
int pfb_message_requeue( const char* msg ) {
return pfb_action ( MSG_REQUEUE, msg );
}
int pfb_message_release( const char* msg ) {
return pfb_action ( MSG_RELEASE, msg );
}
int pfb_set_queue ( int q ) {
if ( q<pfb_queue_count() )
return PFBE_OK;
else
return PFBE_ERROR;
}
void pfb_use_envelope ( int u ) {
}
int pfb_get_caps() {
return pfb_caps;
}
char* pfb_queue_name ( int q ) {
if ( q<pfb_queue_count() )
return q_names[q];
else
return "noname";
}
int pfb_queue_count() {
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1