#include #include #include #include #include #include #include #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= 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