
////////////////////////////////////////////////////////////////////////////////////
// DataOutput: abstract base class for converting rawdata to output

function DataOutput(fname,denylist){
	//abstract class
	this.formatName=fname;
	//denylist can be any non null value
	//if specified, checks whether to use only denies
	if(denylist) this.denyOnly=(settings.denyonly==0);
}

DataOutput.prototype.write=function(arrRules){
	//abstract method declaration
	var stmp;
	var retStr=this.header;
	ui.updateStatus("Writing "+this.formatName+" format: "+arrRules.length+' rules');
	if (this.header!="") ui.debug("DataOutput.write: writing header:\n"+this.header,false);

	for(this.ruleIndex=0;this.ruleIndex<arrRules.length;this.ruleIndex++){
		var rule=arrRules[this.ruleIndex];
		if((this.ruleIndex+1)%10==0) ui.updateStatus("Writing "+this.formatName+" format ("+(this.ruleIndex+1)+"/"+arrRules.length+")");
		//errror handler
		//if(rule.range.startIP==rule.range.endAddr=='0.0.0.0'){
			//cnv.handleException('Data Processing Error writing rule '+this.ruleIndex+': Range is unset.');
		//}else{
			if(!(this.denyOnly && rule.action!="deny")) {
				stmp=this.getString(rule);
				ui.debug("DataOutput.write: writing output:\n"+stmp,false);
				retStr+=stmp;
			}
		//}
	}

	retStr+=this.footer;
	if (this.footer!="") ui.debug("DataOutput.write: writing footer:\n"+this.footer,false);
	ui.getElement("sto").value=retStr;
}

DataOutput.prototype.getString=function(rule){
	throw new CustomError("Method must be overridden",1002,"DataOutput::getString - This method must be overridden");
	//throw("DataOutput.getString(): This method must be overridden");
}
DataOutput.prototype.ruleIndex=-1;
DataOutput.prototype.header="";
DataOutput.prototype.footer="";
DataOutput.prototype.formatName="Unassigned";
DataOutput.prototype.denyOnly=false;

////////////////////////////////////////////////////////////////////////////////////
// The formats in the format DataOutput_<format>

function DataOutput_azureus(){
	this.DataOutput = DataOutput;
	this.DataOutput("Azureus",true);
	this.header="d6:rangesl";
	this.footer="ee";
}
DataOutput_azureus.prototype = new DataOutput;
DataOutput_azureus.prototype.getString=function(rule){
//d11:description23:Vivendi Universal Games3:end12:12.130.6.2555:start12:12.130.6.248e
//d11:description32:Australian Department of Defence3:end14:160.64.255.2555:start10:160.64.0.0e
	return 'd11:description'+this.getAzData(rule.comment)+'3:end'+this.getAzData(rule.range.endAddr)+'5:start'+this.getAzData(rule.range.startAddr)+'e';
//	return rule.comment+':'+rule.range.startAddr+"-"+rule.range.endAddr+"\n";
}
DataOutput_azureus.prototype.getAzData= function(str){
	return str.length+":"+str
}

function DataOutput_bbl(){
	this.DataOutput = DataOutput;
	this.DataOutput("Bob's Block List (BBL)",true);
}
DataOutput_bbl.prototype = new DataOutput;
DataOutput_bbl.prototype.getString=function(rule){

	var out="";
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		bits=snet.getMaskbits();
		var thisout=snet.getStartAddr()+((bits<32)?('/'+bits):"")+' ';
		for(var j=thisout.length;j<16;j++)thisout+=' ';
		out+=thisout+rule.comment+'\n';
	}
	return out;
}



function DataOutput_bearshare(){
	this.DataOutput = DataOutput;
	this.DataOutput("Bearshare",true);
}
DataOutput_bearshare.prototype = new DataOutput;
DataOutput_bearshare.prototype.getString=function(rule){
	//convert the raw rule to output string
	//24.84.58.65
	//216.122.0.0/255.255.0.0
	var out="";
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		out+=snet.getStartAddr();
		if(snet.startIP!=snet.endIP) out+="/"+snet.getMask();
		out+="\n";
	}
	return out;
}


function DataOutput_blackice(){
	this.DataOutput = DataOutput;
	this.DataOutput("BlackICE");
	//stuff to only calculate once...
	var add=parseInt(ui.getComboValue("expiry"));
	if(add>0){
		var dat=new Date(new Date().getTime()+parseInt(add)*86400000);
		this.expiry=this.getBlackICEDate(dat);
	}
	this.creationDate=this.getBlackICEDate(new Date());
}

DataOutput_blackice.prototype = new DataOutput;
DataOutput_blackice.prototype.expiry="PERPETUAL";
DataOutput_blackice.prototype.getString=function(rule){
	//convert the raw rule to output string
	var action=((rule.action=="deny")?"REJECT":"ACCEPT");
	//precedence always 4000?
	var prec="4000"
	var who="bluetack";
	//ips
	var ipaddr=rule.range.startAddr+((rule.range.startAddr==rule.range.endAddr)?"":" - "+rule.range.endAddr);
	var portrange="";
	if (ui.getComboValue("biIniSection")=="low"){
		portrange=":0 - 1023";
	}else if (ui.getComboValue("biIniSection")=="high"){
		portrange=":1024 - 65535";
	}
	return action+", "+ipaddr+portrange+","+rule.comment+", "+this.creationDate+", "+this.expiry+", "+prec+", "+who+"\n";
}

DataOutput_blackice.prototype.getBlackICEDate=function (d){
	return (d.getFullYear()+"-"+this.pad(d.getMonth()+1)+"-"+this.pad(d.getDate())+" "+this.pad(d.getHours())+":"+this.pad(d.getMinutes())+":"+this.pad(d.getSeconds()));
}

DataOutput_blackice.prototype.pad=function(what){
	return ((what < 10) ? "0" : "")+what;
}

function DataOutput_blockpost(){
	this.DataOutput = DataOutput;
	this.DataOutput("Blockpost v1",true);
}
DataOutput_blockpost.prototype = new DataOutput;
DataOutput_blockpost.prototype.getString=function(rule){
	//convert the raw rule to output string
	var out="";

	//63.236.32.50/255.255.255.255,Xupiter.com#P2P Dangerous IPs
	//65.160.0.0/255.255.128.0,OverPeer#P2P Dangerous IPs

	var comment2=ui.getElement("bpcat").value;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		out+=snet.getStartAddr()+'/'+snet.getMask()+','+rule.comment+'#'+comment2+'\n';
	}
	return out;
}

function DataOutput_blockp2(){
	this.DataOutput = DataOutput;
	this.DataOutput("Blockpost v2",true);
	this.header="#BLOCKPOST V2\n";
}
DataOutput_blockp2.prototype = new DataOutput;
DataOutput_blockp2.prototype.getString=function(rule){
	//convert the raw rule to output string
	return "2,"+rule.range.startAddr+"-"+rule.range.endAddr+"#"+rule.comment+"\n";
}


function DataOutput_cidrcmts(){
	this.DataOutput = DataOutput;
	this.DataOutput('CIDR with comments',true);
}
DataOutput_cidrcmts.prototype = new DataOutput;
DataOutput_cidrcmts.prototype.getString=function(rule){

	var out='';
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		bits=snet.getMaskbits();
		out+=snet.getStartAddr()+((bits<32)?('/'+bits):'')+' #'+rule.comment+'\n';
	}
	return out;
}

function DataOutput_ciscoacl(){
	this.DataOutput = DataOutput;
	this.DataOutput("Cisco ACL");
	this.aclnum=ui.getElement("ciscoaclnum").value;
	this.direction=ui.getComboValue("ciscodirection");
	this.header="ip access-group "+this.aclnum+" "+this.direction+"\n";
	this.footer="\n! Warning, permit any\n! If you are fine tuning your ACL,\n! you may wish to modify this\nip access-list "+this.aclnum+" permit any any\n";
}
DataOutput_ciscoacl.prototype = new DataOutput;
DataOutput_ciscoacl.aclnum = "101";
DataOutput_ciscoacl.prototype.getString=function(rule){
	//convert the raw rule to output string
	var out="";
	var bits;
	var snets=rule.range.getSubnets();
	var snet;

	for(var i=0;i<snets.length;i++){
		//access-list 101 deny ip ADDRESS 0.0.0.255 any
		snet=snets[i];
		invMask=snet.getInverseMask();
		out+="access-list "+this.aclnum+" "+((rule.action=='deny')?'deny':'permit')+" ip ";
		if(this.direction=="out"){
			out+="any "+((invMask=="0.0.0.0")?("host "+snet.getStartAddr()):(snet.getStartAddr()+" "+invMask))+"\n";
		}else{
			out+=((invMask=="0.0.0.0")?("host "+snet.getStartAddr()):(snet.getStartAddr()+" "+invMask))+" any\n";
		}
	}
	return out;
}



function DataOutput_ciscoios(){
	this.DataOutput = DataOutput;
	this.DataOutput("Cisco IOS");
	//this.header="ip access-group 101 in|out\n";
}
DataOutput_ciscoios.prototype = new DataOutput;
DataOutput_ciscoios.prototype.getString=function(rule){
	//convert the raw rule to output string
	var out="";
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		invMask=snet.getInverseMask();
		out+=((rule.action=='deny')?'deny':'permit')+" ip ";
		out+=((invMask=="0.0.0.0")?("host "+snet.getStartAddr()):(snet.getStartAddr()+" "+invMask))+" any\n";
	}
	return out;
}

function DataOutput_donk(){
	this.DataOutput = DataOutput;
	this.DataOutput("eDonkey");
}
DataOutput_donk.prototype = new DataOutput;
DataOutput_donk.prototype.getString=function(rule){
	//convert the raw rule to output string
	return this.longIP(rule.range.startAddr)+' - '+this.longIP(rule.range.endAddr)+' , '+((rule.action=='deny')?'100':'200')+' , '+rule.comment+'\n';
}
DataOutput_donk.prototype.longIP=function (addr){
	//make 10.6.30.250 = 010.006.030.250
	var rng='',tmp;
	var b=addr.split(".");
	for(var j=0;j<4;j++) {
		tmp=b[j];
		for(k=tmp.length;k<3;k++) tmp='0'+tmp;
		rng+=(tmp+((j<3)?".":""));
	}
	return rng;
}

//eth ip filter insert forward drop -sa ADDRESS -sm 255.255.255.0
function DataOutput_flowpoint(){
	this.DataOutput = DataOutput;
	this.DataOutput("Flowpoint",true);
}
DataOutput_flowpoint.prototype = new DataOutput;
DataOutput_flowpoint.prototype.getString=function(rule){
	var out="";
	var mask;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		out+="eth ip filter insert forward drop -sa "+snet.getStartAddr()+((snet.getMask()=='255.255.255.255')?"":" -sm "+snet.getMask())+"\n";
	}
	return out;
}


function DataOutput_gnu(){
	this.DataOutput = DataOutput;
	this.DataOutput("Gnucleus",true);
}
DataOutput_gnu.prototype = new DataOutput;
DataOutput_gnu.prototype.getString=function(rule){
	//convert the raw rule to output string
	return rule.range.startAddr+"-"+rule.range.endAddr+':'+rule.comment+':'+'\n';
}


function DataOutput_htaccess(){
	this.DataOutput = DataOutput;
	this.DataOutput("Apache .htaccess",true);
	this.header="order allow,deny\n";
	this.footer='\nErrorDocument 403 "<center><h1>No Freakin\' Way</h1></center><br><br>Your IP appears to be managed by the RIAA,MPAA or someone working to stop the flow of data on the internet, and thus you are not welcome.<br><br>  If you believe you have received this in error or wish to argue about it, contact the site owner.<br><br>Alternatively, you can go back to <a href="http://www.riaa.com">where you came from.</a>\nallow from all\n;';
}

DataOutput_htaccess.prototype = new DataOutput;
DataOutput_htaccess.prototype.getString=function(rule){
	//convert the raw rule to output string
	//deny from 67.117.184
	//return rule.range.startAddr+"-"+rule.range.endAddr+':'+rule.comment+':'+'\n';
	return "deny from "+rule.range.startAddr+"\n";
}


function DataOutput_ipfw(){
	this.DataOutput = DataOutput;
	this.DataOutput('ipfw',true);
	this.ipfwRuleIndex=30000;
}

DataOutput_ipfw.prototype = new DataOutput;
DataOutput_ipfw.prototype.getString=function(rule){

	var out='#'+rule.comment+'\n';
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		bits=snet.getMaskbits();
		out+='add '+(this.ipfwRuleIndex++)+' deny log ip from any to ';
		out+=snet.getStartAddr()+((bits<32)?('/'+bits):'')+'\n';
	}
	return out;
}


function DataOutput_iptables(){
	this.DataOutput = DataOutput;
	this.DataOutput("iptables bash",true);
	this.header='#!/bin/bash\n\n# Create special MLDONKEY chain\niptables -t filter -N MLDONKEY\niptables -t filter -F MLDONKEY\n\n';
	this.header+='# Create the logdrop chain to log & drop a packet\niptables -t filter -N MLDONKEY_LOGDROP\niptables -t filter -F MLDONKEY_LOGDROP\n';
	this.header+='iptables -t filter -A MLDONKEY_LOGDROP -j LOG --log-prefix "MLDONKEY"\niptables -t filter -A MLDONKEY_LOGDROP -j DROP\n\n';
	this.header+='# Jump to the special MLD chain at the end of the INPUT chain (commented out)\n#iptables -t nat -A INPUT -j MLDONKEY\n\n# List of ip ranges to ban\n';
}
DataOutput_iptables.prototype = new DataOutput;
DataOutput_iptables.prototype.getString=function(rule){
	//convert the raw rule to output string
	//iptables -t filter -I INPUT 1 -s 208.225.90.0/24  -j MLDONKEY_LOGDROP
	var out="";
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		bits=snet.getMaskbits();
		out+="iptables -t filter -I INPUT 1 -s "+snet.getStartAddr()+((bits<32)?('/'+bits):"")+' -j MLDONKEY_LOGDROP\n';
	}
	return out;
}

function DataOutput_kpf(){
	this.DataOutput = DataOutput;
	this.DataOutput("Kerio v2");
	this.logging=(settings.logging==0);
}

DataOutput_kpf.prototype = new DataOutput;
DataOutput_kpf.prototype.logging;
DataOutput_kpf.prototype.getString=function(rule){
	//convert the raw rule to output string
	//USES EITHER RANGES OR NETMASKS (ranges only in this implementation)
	var kpfrange=((rule.range.startIP==rule.range.endIP)?'0.0.0.0':rule.range.endAddr);
	var output='INSERT Config.FwCfg.Rules.FilterRule SET\n';

	output+='RuleDescription =  "'+rule.comment+'",\n';
	output+='Application =  "",\n';
	output+='Enabled =  "1",\n';
	output+='Type =  "3",\n';
	output+='Protocol =  "0",\n';
	output+='ProtocolNumber =  "0",\n';
	output+='IcmpType =  "16",\n';
	//1 for permit, 3 for deny
	output+='Action =  "'+((rule.action=="deny")?3:1)+'",\n';
	output+='ValidTime.AlwaysValid =  "1",\n';
	output+='Logging =  "'+((this.logging)?'1':'0')+'",\n';
	output+='LocalEndpoint.Port.Type =  "0",\n';
	output+='LocalEndpoint.Port.sValue =  "",\n';
	output+='RemoteEndpoint.Port.Type = "0",\n';
	output+='RemoteEndpoint.Port.sValue = "",\n';
	output+='RemoteEndpoint.Address.Type =  "'+((kpfrange=="0.0.0.0")?1:3)+'",\n';
	output+='RemoteEndpoint.Address.Id =  "0",\n';
	output+='RemoteEndpoint.Address.Value1 =  "'+rule.range.startAddr+'",\n';
	output+='RemoteEndpoint.Address.Value2 =  "'+kpfrange+'",\n';
	output+='CmdsRuleId =  "0",\n';
	output+='Order =  "'+((46137344)+(this.ruleIndex*4194304))+'";\n\n';
	return output;
}

function DataOutput_kp4(){
	this.DataOutput = DataOutput;
	this.DataOutput("Kerio v4");
	this.logging=(settings.logging==0);
}
DataOutput_kp4.prototype = new DataOutput;
DataOutput_kp4.prototype.logging;
DataOutput_kp4.prototype.getString=function(rule){
	var output='  <listitem>\n';
	output+='    <variable name="Enabled">1</variable>\n';
	output+='    <variable name="Description">'+rule.comment+'</variable>\n';
	output+='    <variable name="Application">any</variable>\n';
	output+='    <variable name="Order">'+(1000+this.ruleIndex)+'</variable>\n';
	output+='    <variable name="Action">'+((rule.action=="deny")?'deny':'permit')+((this.logging)?',log':'')+'</variable>\n';
	output+='    <variable name="Condition">direc=both &amp; ';
	if(rule.range.startIP==rule.range.endIP){
		output+='raddr='+rule.range.startAddr;
	}else{
		output+='(raddr&gt;='+rule.range.startAddr+' &amp; raddr&lt;='+rule.range.endAddr+')';
	}
	output+='</variable>\n';
	output+='    <variable name="ValidTime">always</variable>\n';
	output+='    <variable name="Id">0</variable>\n';
	output+='    <variable name="Group">Default</variable>\n';
	output+='  </listitem>\n';
	return output;
}

function DataOutput_kwr5(){
	this.DataOutput = DataOutput;
	this.DataOutput("Kerio WinRoute 5");
	//this.logging=(settings.kpflogging==0);
	this.header='<list name="TrafficRules">\n';
	this.footer='</list>\n';
}
DataOutput_kwr5.prototype = new DataOutput;
DataOutput_kwr5.prototype.logging;
DataOutput_kwr5.prototype.getString=function(rule){
	var output='  <listitem>\n';
	output+='    <variable name="Order">'+(1000+this.ruleIndex)+'</variable>\n';
	output+='    <variable name="Enabled">1</variable>\n';
	output+='    <variable name="Color">4</variable>\n';
	output+='    <variable name="Name">Converted Blocklist</variable>\n';
	output+='    <variable name="Description">'+rule.comment+'</variable>\n';
	output+='    <variable name="Application">any</variable>\n';
	output+='    <variable name="Action">'+((rule.action=="deny")?'deny':'permit')+((this.logging)?',log':'')+'</variable>\n';
	output+='    <variable name="Src">'+rule.range.startAddr+'-'+rule.range.endAddr+'</variable>\n';
	output+='    <variable name="Dst"></variable>\n';
	output+='    <variable name="Proxy"></variable>\n';
	output+='    <variable name="Service"></variable>\n';
	output+='    <variable name="ValidTime"></variable>\n';
	output+='    <variable name="Action">drop,logpkt</variable>\n';
	output+='    <variable name="SNAT"></variable>\n';
	output+='    <variable name="DNAT"></variable>\n';
	output+='  </listitem>\n';
	return output;
}

function DataOutput_morph(){
	this.DataOutput = DataOutput;
	this.DataOutput("Morpheus",true);
}

DataOutput_morph.prototype = new DataOutput;
DataOutput_morph.prototype.getString=function(rule){
	//convert the raw rule to output string
	return rule.range.startAddr+"-"+rule.range.endAddr+':'+rule.comment+':'+'\n';
}

function DataOutput_pg(){
	this.DataOutput = DataOutput;
	this.DataOutput("PeerGuardian",true);
}
DataOutput_pg.prototype = new DataOutput;
DataOutput_pg.prototype.getString=function(rule){
if(rule.range.startAddr!=rule.range.endAddr){
		return rule.comment+':'+rule.range.startAddr+"-"+rule.range.endAddr+"\n";
	}else{
		return rule.comment+':'+rule.range.startAddr+((settings.singleAsRanges==0)?"-"+rule.range.endAddr:"")+"\n";
	}
}

function DataOutput_pgipdbsql(){
	this.DataOutput = DataOutput;
	this.DataOutput("PGIPDB SQL",true);
	this.sqlruleoffset=0;
}
DataOutput_pgipdbsql.prototype = new DataOutput;
DataOutput_pgipdbsql.prototype.getString=function(rule){
	//INSERT INTO pgdat VALUES("1", "RIAA", "208.225.90.0", "208.225.90.255", "method", "METH", "360", "215", "0");
	this.sqlruleoffset++;
	return 'INSERT INTO list VALUES("'+this.sqlruleoffset+'", "0", "2004-06-18", "'+rule.range.startAddr+'#'+rule.range.endAddr+'", "'+rule.comment+'");\n';
}


function DataOutput_phex(){
	this.DataOutput = DataOutput;
	this.DataOutput("Phex",true);
	this.header='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<phex phex-version="0.9.5.57">\n<security>\n';
	this.footer='</security>\n</phex>';
}

DataOutput_phex.prototype = new DataOutput;
DataOutput_phex.prototype.getString=function(rule){
	out='<ip-access-rule>\n<description>'+rule.comment+'</description>\n<isDenyingRule>true</isDenyingRule>\n';
	out+='<isDisabled>false</isDisabled>\n<expiryDate>9223372036854775807</expiryDate>\n';
	out+='<isDeletedOnExpiry>false</isDeletedOnExpiry>\n';
	out+='<addressType>'+((rule.range.startAddr==rule.range.endAddr)?1:3)+'</addressType>\n';
	out+='<ip>'+rule.range.getStartAddrHex()+'</ip>\n';
	out+=((rule.range.startAddr==rule.range.endAddr)?'':'<compareIP>'+rule.range.getEndAddrHex()+'</compareIP>\n');
	out+='</ip-access-rule>\n';
	return out;
}


function DataOutput_plainrange(){
	this.DataOutput = DataOutput;
	this.DataOutput("Plain IP Ranges",true);
}
DataOutput_plainrange.prototype = new DataOutput;
DataOutput_plainrange.prototype.getString=function(rule){
	if(rule.range.startAddr!=rule.range.endAddr){
		return rule.range.startAddr+"-"+rule.range.endAddr+"\n";
	}else{
		return rule.range.startAddr+((settings.singleAsRanges==0)?"-"+rule.range.endAddr:"")+"\n";
	}
}

function DataOutput_plainrangecs(){
	this.DataOutput = DataOutput;
	this.DataOutput("Plain Ranges - Comma Seperated",true);
}
DataOutput_plainrangecs.prototype = new DataOutput;
DataOutput_plainrangecs.prototype.getString=function(rule){
	return rule.range.startAddr+"-"+rule.range.endAddr+",";
}

function DataOutput_raza(){
	this.DataOutput = DataOutput;
	this.DataOutput('Shareaza xml');
	this.header='<?xml version="1.0"?>\n<security xmlns="http://www.shareaza.com/schemas/Security.xsd">\n';
	this.footer="</security>\n"
}
DataOutput_raza.prototype = new DataOutput;
DataOutput_raza.prototype.getString=function(rule){

	var out='';
	var snet;

	try{
		var cmt=rule.comment.replace(new RegExp ('"', 'gi'), "'");
		var snets=rule.range.getSubnets();
		for(var i=0;i<snets.length;i++){
			snet=snets[i];
			//if (!snet) throw new CustomError("Subnetting Error",1005,"Unable to convert range into subnets - Rule "+this.ruleIndex+": "+rule.comment);
			//alert("here "+(i+1)+"/"+snets.length);
			out+='<rule address="'+snet.getStartAddr()+'" action="'+((rule.action=="deny")?"deny":"accept")+'" type="address"';
			out+=((snet.getMask()=='255.255.255.255')?'':' mask="'+snet.getMask()+'"');
			out+=this.getExpiry()+' comment="'+cmt+'"/>\n';
		}
	} catch(e){
		//convert to provide stacktrace
		throw new CustomError(e.name, (e.number & 0xFFFF), e.message)
	}
	return out;
}

DataOutput_raza.prototype.getExpiry=function(){
	var expire='';
	var add=parseInt(ui.getComboValue('expiry'));
	if(add>0){
		var dat=new Date();
		expire=' expire="'+(parseInt(dat.getTime()/1000)+(parseInt(add)*86400))+'"';
	}
	return expire;
}

function DataOutput_shorewall(){
	this.DataOutput = DataOutput;
	this.DataOutput('CIDR',true);
}
DataOutput_shorewall.prototype = new DataOutput;
DataOutput_shorewall.prototype.getString=function(rule){

	var out='';
	var bits;
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		bits=snet.getMaskbits();
		out+=snet.getStartAddr()+((bits<32)?('/'+bits):'')+'\n';
	}
	return out;
}

function DataOutput_smoothie(){
	this.DataOutput = DataOutput;
	this.DataOutput('Smoothwall',true);
	this.logging=(settings.logging==0);
}

DataOutput_smoothie.prototype = new DataOutput;
DataOutput_smoothie.prototype.getString=function(rule){

/**
#no logging
0.0.0.0/8,off,DROP,on
#with logging
1.0.0.0/8,on,DROP,on
**/
	var out="";
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		out+=snet.getStartAddr();
		if(snet.startIP!=snet.endIP) out+="/"+snet.getMaskbits();
		out+=','+((this.logging)?'on':'off')+',DROP,on\n';
	}
	return out;
}

function DataOutput_snort(){
	this.DataOutput = DataOutput;
	this.DataOutput('Snort',true);
}

DataOutput_snort.prototype = new DataOutput;
DataOutput_snort.prototype.getString=function(rule){
	var out="";
	var snets=rule.range.getSubnets();
	var snet;
	for(var i=0;i<snets.length;i++){
		snet=snets[i];
		out+='alert tcp '+snet.getStartAddr();
		if(snet.startIP!=snet.endIP) out+=":"+snet.getMask();

		var cmt=rule.comment.replace(new RegExp ('[(]', 'gi'), "");
		cmt=cmt.replace(new RegExp ('[)]', 'gi'), "");

		out+=' any <> $HOME_NET any (msg:"'+cmt+'"; classtype:trojan-activity; priority:1;)\n';
	}
	return out;
}

function DataOutput_sygate(){
	this.DataOutput = DataOutput;
	this.DataOutput('Sygate',true);
	this.advRuleCount=0;
	this.header='The Sygate Advanced Rules output is split into multiple rules for efficiency.\nPaste each of the sections into a seperate rule for better performance.\n\n';
	//this.footer=this.snipend();
}

DataOutput_sygate.prototype = new DataOutput;
DataOutput_sygate.prototype.getString=function(rule){
		ret = '';
		//every 400 ranges, split out the rules
		if (this.ruleIndex%400==0){
			if (this.advRuleCount!=0) ret+=rule.range.startAddr+'-'+rule.range.endAddr+'\n\nX========= END RULE '+this.advRuleCount+' =========X\n';
			this.advRuleCount++;
			ret+='X========= BEGIN RULE '+this.advRuleCount+' =========X\n\n';
			if (this.advRuleCount==0) ret+= rule.range.startAddr+'-'+rule.range.endAddr+',';
			this.footer = '\n\nX========= END RULE '+this.advRuleCount+' =========X\n';
			return ret;
		}else{
			return rule.range.startAddr+'-'+rule.range.endAddr+',';
		}
}

function DataOutput_trusty(){
	this.DataOutput = DataOutput;
	this.DataOutput('TrustyFiles',true);
}
DataOutput_trusty.prototype = new DataOutput;
DataOutput_trusty.prototype.getString=function(rule){
	//convert the raw rule to output string
	return rule.range.startAddr+"-"+rule.range.endAddr+':'+rule.comment+':'+'\n';
}

function DataOutput_zonealarm(){
	this.DataOutput = DataOutput;
	this.DataOutput("ZoneAlarm v4 xml");
	this.header='<zones>\n';
	this.footer='</zones>\n';
	this.zonetype='unknown';
	//this format REQUIRES SortByRuleType (which puts permits before denies)
	//it will also only output addresses or ranges, as they require less computation
}
DataOutput_zonealarm.prototype.zonetype; //for stateful inspection of rule action
DataOutput_zonealarm.prototype = new DataOutput;
DataOutput_zonealarm.prototype.getString=function(rule){
	var out='';
	if(this.zonetype=='unknown'){
		if(rule.action=='deny'){
			out+='<restricted clearOldEntries="true" defaultNetworkStatus="ask" defaultAdapterMode="off">\n';
			this.footer='</restricted>\n</zones>\n';
		}else{
			out+='<trusted clearOldEntries="true" defaultNetworkStatus="ask" defaultAdapterMode="off">\n';
			this.footer='</trusted>\n</zones>\n';
		}
		this.zonetype=rule.action;
	}else if(this.zonetype!=rule.action){
		//switch from one mode to another
		if(rule.action=='deny'){
			out+='</trusted>\n<restricted clearOldEntries="true" defaultNetworkStatus="ask" defaultAdapterMode="off">\n';
			this.footer='</restricted>\n</zones>\n';
		}else{
			out+='</restricted>\ntrusted clearOldEntries="true" defaultNetworkStatus="ask" defaultAdapterMode="off">\n';
			this.footer='</trusted>\n</zones>\n';
		}
		this.zonetype=rule.action;
	}
	//now work out the output for the rule
	var cmt=rule.comment.replace(new RegExp ('"', 'gi'), ""); //remove double quotes
	cmt=cmt.replace(new RegExp ("'", 'gi'), ""); //remove apostrophes
	cmt=cmt.replace(new RegExp ('<', 'gi'), ""); //remove greater than
	cmt=cmt.replace(new RegExp ('>', 'gi'), ""); //remove less than
	cmt=cmt.replace(new RegExp ('&', 'gi'), "and"); //change ampersands for "and"
	cmt=cmt.replace(new RegExp ('[|]', 'gi'), ""); //remove pipe
	var sc;
	for (var i=0;i<32;i++){
		sc='\\x'+decToHex(i);
		cmt=cmt.replace(new RegExp (sc, 'gi'), "");
	}
	for (i=127;i<256;i++){
		sc='\\x'+decToHex(i);
		cmt=cmt.replace(new RegExp (sc, 'gi'), "");
	}
	if(rule.range.startIP==rule.range.endIP){
		out+='<ipaddr address="'+rule.range.startAddr+'" status="true" description="'+cmt+'"/>\n';
	}else{
		out+='<iprange address="'+rule.range.startAddr+'" toAddress="'+rule.range.endAddr+'" status="true" description="'+cmt+'"/>\n';
	}
	return out;
}
