/** * Author: Carl Glaysher * Date Created: 17/03/2012 * Description: Module to emulate SPAMC client in a node way * Available Commands: * * ping - returns boolean * check - returns object * symbols - returns object with matches * report - returns objects with matches and descriptions * reportIfSpam - returns object with matches and descriptions * process - returns object with modified message * headers - returns object with modified headers only * learn - TELL spamassassin message is Spam or Ham * tell - TELL spamassassin message is Spam * revoke - remove Spammed Message as being spam from spamassassin * */ var net = require('net'); var spamc = function (host, port, timeout) { var self = this; var protocolVersion = 1.5; var host = (host == undefined) ? '127.0.0.1' : host; var port = (port == undefined) ? 783 : port; var connTimoutSecs = (timeout == undefined) ? 10 : timeout; /* * Description: Sends a Ping to spamd and returns Pong on response * Param: onResponse {function} * Returns: self */ this.ping = function(onResponse){ exec('PING',null,function(data){ /* Check Response has the word PONG */ if(data[0].indexOf('PONG')>0){ onResponse(true); }else{ onResponse(false); } }); return self; }; /* * Description: returns spam score * Param: message {string} * Param: onResponse {function} * Returns: self */ this.check = function(message,onResponse){ exec('CHECK',message,function(data){ var response = processResponse('CHECK',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Returns Spam Score and Matches * Param: message {string} * Param: onResponse {function} * Returns: self */ this.symbols = function(message,onResponse){ exec('SYMBOLS',message,function(data){ var response = processResponse('SYMBOLS',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Returns an object report * Param: message {string} * Param: onResponse {function} * Returns: self */ this.report = function(message,onResponse){ exec('REPORT',message,function(data){ var response = processResponse('REPORT',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Returns Object Report if is spam * Param: message {string} * Param: onResponse {function} * Returns: self */ this.reportIfSpam = function(message,onResponse){ exec('REPORT_IFSPAM',message,function(data){ var response = processResponse('REPORT_IFSPAM',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Returns back a report for the message + the message * Param: message {string} * Param: onResponse {function} * Returns: self */ this.process = function(message,onResponse){ exec('PROCESS',message,function(data){ var response = processResponse('PROCESS',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Returns headers for the message * Param: message {string} * Param: onResponse {function} * Returns: self */ this.headers = function(message,onResponse){ exec('HEADERS',message,function(data){ var response = processResponse('HEADERS',data); if(typeof(onResponse)=='function') onResponse(response); }); return self; }; /* * Description: Tell spamd to learn message is spam/ham or forget * Param: message {string} * Param: learnType {string} * Param: onResponse {function} * Returns: self */ this.learn = function(message,learnType,onResponse){ var headers; switch(learnType.toUpperCase()){ case 'SPAM': headers=[ {name:'Message-class','value':'spam'}, {name:'Set','value':'local'} ]; break; case 'HAM': case 'NOTSPAM': case 'NOT_SPAM': headers=[ {name:'Message-class','value':'ham'}, {name:'Set','value':'local'} ]; break; case 'FORGET': headers=[ {name:'Remove','value':'local'} ]; break; default: throw new Error('Learn Type Not Found'); } exec('TELL',message,function(data){ var response = processResponse('HEADERS',data); if(response.responseCode==69){ throw new Error('TELL commands are not enabled, set the --allow-tell switch.'); } if(typeof(onResponse)=='function') onResponse(response); },headers); return self; }; /* * Description: tell spamd message is not spam * Param: message {string} * Param: onResponse {function} * Returns: self */ this.revoke = function(message,onResponse){ headers=[ {name:'Message-class','value':'ham'}, {name:'Set','value':'local,remote'} ]; exec('TELL',message,function(data){ var response = processResponse('HEADERS',data); if(response.responseCode==69){ throw new Error('TELL commands are not enabled, set the --allow-tell switch.'); } if(typeof(onResponse)=='function') onResponse(response); },headers); return self; }; /* * Description: Tell spamd message is spam * Param: message {string} * Param: onResponse {function} * Returns: self */ this.tell = function(message,onResponse){ headers=[ {name:'Message-class','value':'spam'}, {name:'Set','value':'local,remote'} ]; exec('TELL',message,function(data){ var response = processResponse('HEADERS',data); if(response.responseCode==69){ throw new Error('TELL commands are not enabled, set the --allow-tell switch.'); } if(typeof(onResponse)=='function') onResponse(response); },headers); return self; }; /* * Description: Sends a command to spamd * Param: cmd {string} * Param: message {string} * Param: onData {function(data)} */ var exec = function(cmd,message,onData,extraHeaders){ var responseData = []; var stream = net.createConnection(port,host); stream.setTimeout(connTimoutSecs*1000,function(){ throw new Error('Connection to spamd Timed Out'); }); stream.on('connect',function(){ /* Create Command to Send to spamd */ cmd = cmd+" SPAMC/"+protocolVersion+"\r\n"; if(typeof(message)=='string'){ message = message+'\r\n'; cmd = cmd+"Content-length: "+(message.length)+"\r\n"; /* Process Extra Headers if Any */ if(typeof(extraHeaders)=='object'){ for(var i=0;i0){ responseData[responseData.length]=data[i]; } } }); stream.on('close',function(){ onData(responseData); }) }; /* * Description: Processes Response from spamd and put into a formatted object * Param: cmd {string} * Param: lines {array[string]} * Return: {object} */ var processResponse = function(cmd,lines){ var returnObj = {}; var result = lines[0].match(/SPAMD\/([0-9\.]+)\s([0-9]+)\s([0-9A-Z_]+)/); if(result==null){ throw new Error('spamd unreconized response:'+lines[0]); } returnObj.responseCode = parseInt(result[2]); returnObj.responseMessage = result[3]; if(cmd=='TELL'){ returnObj.didSet=false; returnObj.didRemove=false; } for(var i=0;i=0){ returnObj.didSet=true; } if(lines[i].indexOf('DidRemove:')>=0){ returnObj.didRemove=true; } } if(cmd=='PROCESS'){ returnObj.message = ''; for(var i=3;i