#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <syslog.h>
#include "pfq_backend.h"
#include "pfq_service.h"
#include "../pfqmessage.h"
#include "../config.h"
int CURQ;
int NUMMSG_THREAD;
char queue_path[BUF_SIZE];
char config_path[BUF_SIZE];
char pftools_path[BUF_SIZE];
char postconf_path[BUF_SIZE];
char postsuper_path[BUF_SIZE];
char postcat_path[BUF_SIZE];
int has_configpath;
#define HEADER_FROM "From: "
#define HEADER_TO "To: "
#define HEADER_SUBJECT "Subject: "
#define HEADER_FROM_LEN 6
#define HEADER_TO_LEN 4
#define HEADER_SUBJECT_LEN 9
#define ENVELOPE_FROM "sender: "
#define ENVELOPE_TO "recipient: "
#define ENVELOPE_FROM_LEN 8
#define ENVELOPE_TO_LEN 11
#define ENVELOPE_NULL_SENDER "Null envelope sender"
char *q_names[]={
"deferred",
"hold",
"incoming",
"active"
};
struct pfb_conf_t pfb_conf;
struct pfb_conf_t *pfb_getconf() {
return &pfb_conf;
}
int pfb_apiversion() {
return PFQ_API_VERSION;
}
const char* pfb_id() {
return "postfix 1.x";
}
const char* pfb_version() {
return "1.2";
}
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;
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 ) ) {
msg = &(my_queue[NUMMSG_THREAD]);
memcpy ( msg->id, dir->d_name, sizeof(msg->id) );
snprintf ( msg->path, sizeof(msg->path), "%s/%s",
basedir, dir->d_name );
msg->changed = strcmp( dir->d_name, ext_queue[NUMMSG_THREAD].id );
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 ) {
char pconf[BUF_SIZE];
FILE *p;
msg_max = pfb_conf.msg_max;
dig_limit = pfb_conf.scan_limit;
ext_queue = qptr1;
my_queue = qptr2;
CURQ = 0;
pfb_using_envelope = 0;
pfb_caps = BECAPS_MSG_HOLD | BECAPS_MSG_DEL | BECAPS_MSG_REQUEUE | BECAPS_MSG_ENVELOPE;
memset ( config_path, 0, sizeof(config_path) );
memset ( pftools_path, 0, sizeof(pftools_path) );
memset ( postconf_path, 0, sizeof(postconf_path) );
memset ( postsuper_path, 0, sizeof(postsuper_path) );
memset ( postcat_path, 0, sizeof(postcat_path) );
if ( strlen(pfb_conf.command_path) )
snprintf ( pftools_path, BUF_SIZE-1, "%s", pfb_conf.command_path );
if ( strlen(pfb_conf.config_path) ) {
snprintf ( config_path, BUF_SIZE-1, "%s", pfb_conf.config_path );
has_configpath = 1;
}
// If -p is not specified, use commands without path
if ( strlen ( pftools_path ) ) {
snprintf ( postconf_path, BUF_SIZE, "%s/postconf", pftools_path );
snprintf ( postsuper_path, BUF_SIZE, "%s/postsuper", pftools_path );
snprintf ( postcat_path, BUF_SIZE, "%s/postcat", pftools_path );
} else {
snprintf ( postconf_path, BUF_SIZE, "postconf" );
snprintf ( postsuper_path, BUF_SIZE, "postsuper" );
snprintf ( postcat_path, BUF_SIZE, "postcat" );
}
// Look for queue_directory
if ( has_configpath )
snprintf ( pconf, BUF_SIZE, "%s -c %s -h queue_directory 2> /dev/null", postconf_path, config_path );
else
snprintf ( pconf, BUF_SIZE, "%s -h queue_directory 2> /dev/null", postconf_path );
p = popen ( pconf, "r" );
if ( !p ) {
syslog ( LOGLEVEL, "pfqueue postfix1 backend: cannot use postconf to search queue_directory, command was: \"%s\"", pconf );
pclose ( p );
return PFBE_UNUSABLE;
}
if ( !freadl ( p, queue_path, sizeof(queue_path) ) ) {
syslog ( LOGLEVEL, "pfqueue postfix1 backend: cannot use postconf to search queue_directory, command was: \"%s\"", pconf );
pclose ( p );
return PFBE_UNUSABLE;
}
pclose ( p );
return PFBE_OK;
}
int pfb_close() {
return PFBE_OK;
}
int pfb_fill_queue() {
char buf[BUF_SIZE];
NUMMSG_THREAD = 0;
snprintf ( buf, sizeof(buf), "%s/%s", queue_path, q_names[CURQ] );
dir_dig(buf);
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;
if ( has_configpath )
snprintf ( buf, BUF_SIZE, "%s -c %s %s 2> /dev/null",
postcat_path, config_path, msg->path );
else
snprintf ( buf, BUF_SIZE, "%s %s 2> /dev/null",
postcat_path, msg->path );
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 );
if ( pfb_using_envelope ) {
l1 = ENVELOPE_FROM_LEN;
l2 = ENVELOPE_TO_LEN;
s1 = ENVELOPE_FROM;
s2 = ENVELOPE_TO;
} else {
l1 = HEADER_FROM_LEN;
l2 = HEADER_TO_LEN;
s1 = HEADER_FROM;
s2 = HEADER_TO;
}
while ( (f1==0||f2==0||f3==0) && freadl ( p, buf, BUF_SIZE ) ) {
if ( !f1 && ( !strncmp ( buf, s1, l1 ) ) ) {
memcpy ( msg->from, buf+l1, sizeof(msg->from) );
if ( !strlen(msg->from) )
strcpy ( msg->from, ENVELOPE_NULL_SENDER );
f1++;
}
if ( !f2 && ( !strncmp ( buf, s2, l2 ) ) ) {
memcpy ( msg->to, buf+l2, sizeof(msg->to) );
f2++;
}
if ( !f3 && !strncmp ( buf, HEADER_SUBJECT, HEADER_SUBJECT_LEN ) ) {
memcpy ( msg->subj, buf+HEADER_SUBJECT_LEN, 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];
char buf2[BUF_SIZE];
char *c;
struct msg_t *msg;
msg = msg_from_id(msgid);
if ( !msg )
return 2;
if ( msg->scached )
return 1;
if ( CURQ == Q_DEFERRED ) {
// replace 'deferred' with 'defer'
c = strstr ( msg->path, "deferred" );
if ( c ) {
memset ( buf, 0, sizeof(buf) );
strncpy ( buf, msg->path, c - msg->path );
sprintf ( buf2, "%sdefer%s", buf, c+8 );
}
p = fopen ( buf2, "r" );
if ( !p )
strcpy ( msg->stat, "Deferred, no reason" );
else {
freadl ( p, msg->stat, sizeof(msg->stat) );
}
if ( p )
fclose ( p );
} else if ( CURQ == Q_ACTIVE )
strcpy ( msg->stat, "Active" );
else if ( CURQ == Q_HOLD )
strcpy ( msg->stat, "Held" );
else if ( CURQ == Q_INCOMING )
strcpy ( msg->stat, "Incoming" );
msg->scached = 1;
return 1;
}
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;
if ( has_configpath )
snprintf ( b, BUF_SIZE, "%s -c %s %s 2> /dev/null",
postcat_path, config_path, msg->path );
else
snprintf ( b, BUF_SIZE, "%s %s 2> /dev/null",
postcat_path, msg->path );
p = popen ( b, "r" );
if ( !p )
return PFBE_MSGNOTEX;
j = fread( buffer, sizeof(char), buflen, p );
pclose ( p );
return j;
}
int pfb_action(int act, const char* msg) {
char b[BUF_SIZE];
char o;
switch ( act ) {
case MSG_DELETE:
o = 'd';
break;
case MSG_HOLD:
o = 'h';
break;
case MSG_RELEASE:
o = 'H';
break;
case MSG_REQUEUE:
o = 'r';
break;
default:
return 1;
}
if ( has_configpath )
snprintf ( b, BUF_SIZE, "%s -c %s -%c %s 2>/dev/null",
postsuper_path, config_path, o, msg );
else
snprintf ( b, BUF_SIZE, "%s -%c %s 2>/dev/null",
postsuper_path, o, msg );
system ( b );
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 ) {
CURQ = q;
return PFBE_OK;
}
void pfb_use_envelope ( int u ) {
pfb_using_envelope = u;
}
int pfb_get_caps() {
return pfb_caps;
}
char* pfb_queue_name ( int q ) {
if ( q<=4 )
return q_names[q];
else
return "noname";
}
int pfb_queue_count() {
return 4;
}
syntax highlighted by Code2HTML, v. 0.9.1