Converting JSP code to JavaScript

Hi,
I am trying to implement a new payment system for my largest client who are hoping to move to CyberSource as a payment gateway.
I have previously implemented payments thru WorldPay & Protx/SagePay by ‘simulating’ a web page doing an HTTPS POST, but CyberSource create a unique include file that holds the clients ‘keys’ for security and the include file can be generated in PHP, JSP, ASP, VB or CS (C#).
I thought that trying to ‘translate’ the JSP into JavaScript might be the easiest as I know there is some access to some Java stuff in Servoy (I do not know PHP, JSP, ASP, VB or C#), but I am getting stuck and was hoping someone here might be able to help.
Part of the include file calls some SHA1 functions to encrypt data etc. and I found a JavaScript module that seemed to do all of that

/**
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 * 
 */
var hexcase = 0;

/**
 * hex output format. 0 - lowercase; 1 - uppercase
 * 
 */
var b64pad = "";

/**
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 *
 */
function hex_sha1 ( s )
{
	return rstr2hex ( rstr_sha1 ( str2rstr_utf8 ( s ) ) );
}

function b64_sha1 ( s )
{
	return rstr2b64 ( rstr_sha1 ( str2rstr_utf8 ( s ) ) );
}

function any_sha1 ( s, e )
{
	return rstr2any ( rstr_sha1 ( str2rstr_utf8 ( s ) ), e );
}

function hex_hmac_sha1 ( k, d )
{
	return rstr2hex ( rstr_hmac_sha1 ( str2rstr_utf8 ( k ), str2rstr_utf8 ( d ) ) );
}

function b64_hmac_sha1 ( k, d )
{
	return rstr2b64 ( rstr_hmac_sha1 ( str2rstr_utf8 ( k ), str2rstr_utf8 ( d ) ) );
}

function any_hmac_sha1 ( k, d, e )
{
	return rstr2any ( rstr_hmac_sha1 ( str2rstr_utf8 ( k ), str2rstr_utf8 ( d ) ), e );
}

/**
 * Perform a simple self-test to see if the VM is working
 *
 */
function sha1_vm_test ()
{
	return hex_sha1 ( "abc" ).toLowerCase ( ) == "a9993e364706816aba3e25717850c26c9cd0d89d";
}

/**
 * Calculate the SHA1 of a raw string
 *
 */
function rstr_sha1 ( s )
{
	return binb2rstr ( binb_sha1 ( rstr2binb ( s ), s.length * 8 ) );
}

/**
 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
 *
 */
function rstr_hmac_sha1 ( key, data )
{
	var bkey = rstr2binb ( key );
	if ( bkey.length > 16 ) bkey = binb_sha1 ( bkey, key.length * 8 );

	var ipad = Array ( 16 ), opad = Array ( 16 );
	for ( var i = 0; i < 16; i++ )
	{
		ipad[i] = bkey[i] ^ 0x36363636;
		opad[i] = bkey[i] ^ 0x5C5C5C5C;
	}

	var hash = binb_sha1 ( ipad.concat ( rstr2binb ( data ) ), 512 + data.length * 8 );
	return binb2rstr ( binb_sha1 ( opad.concat ( hash ), 512 + 160 ) );
}

/**
 * Convert a raw string to a hex string
 *
 */
function rstr2hex ( input )
{
	try
	{
		hexcase
	}
	catch ( e )
	{
		hexcase = 0;
	}
	var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
	var output = "";
	var x;
	for ( var i = 0; i < input.length; i++ )
	{
		x = input.charCodeAt ( i );
		output += hex_tab.charAt ( ( x >>> 4 ) & 0x0F )
		+ hex_tab.charAt ( x & 0x0F );
	}
	return output;
}

/**
 * Convert a raw string to a base-64 string
 *
 */
function rstr2b64 ( input )
{
	try
	{
		b64pad
	}
	catch ( e )
	{
		b64pad = '';
	}
	var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	var output = "";
	var len = input.length;
	for ( var i = 0; i < len; i += 3 )
	{
		var triplet = ( input.charCodeAt ( i ) << 16 )
			| ( i + 1 < len ? input.charCodeAt ( i + 1 ) << 8 : 0 )
			| ( i + 2 < len ? input.charCodeAt ( i + 2 ) : 0 );
		for ( var j = 0; j < 4; j++ )
		{
			if ( i * 8 + j * 6 > input.length * 8 ) output += b64pad;
			else output += tab.charAt ( ( triplet >>> 6 * ( 3 - j ) ) & 0x3F );
		}
	}
	return output;
}

/**
 * Convert a raw string to an arbitrary string encoding
 *
 */
function rstr2any ( input, encoding )
{
	var divisor = encoding.length;
	var remainders = Array ( );
	var i, q, x, quotient;

	/* Convert to an array of 16-bit big-endian values, forming the dividend */
	var dividend = Array ( Math.ceil ( input.length / 2 ) );
	for ( i = 0; i < dividend.length; i++ )
	{
		dividend[i] = ( input.charCodeAt ( i * 2 ) << 8 ) | input.charCodeAt ( i * 2 + 1 );
	}

	/*
	 * Repeatedly perform a long division. The binary array forms the dividend,
	 * the length of the encoding is the divisor. Once computed, the quotient
	 * forms the dividend for the next step. We stop when the dividend is zero.
	 * All remainders are stored for later use.
	 */
	while ( dividend.length > 0 )
	{
		quotient = Array ( );
		x = 0;
		for ( i = 0; i < dividend.length; i++ )
		{
			x = ( x << 16 ) + dividend[i];
			q = Math.floor ( x / divisor );
			x -= q * divisor;
			if ( quotient.length > 0 || q > 0 )
				quotient[quotient.length] = q;
		}
		remainders[remainders.length] = x;
		dividend = quotient;
	}

	/* Convert the remainders to the output string */
	var output = "";
	for ( i = remainders.length - 1; i >= 0; i-- )
		output += encoding.charAt ( remainders[i] );

	/* Append leading zero equivalents */
	var full_length = Math.ceil ( input.length * 8 /
		( Math.log ( encoding.length ) / Math.log ( 2 ) ) )
	for ( i = output.length; i < full_length; i++ )
		output = encoding[0] + output;

	return output;
}

/**
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 *
 */
function str2rstr_utf8 ( input )
{
	var output = "";
	var i = -1;
	var x, y;

	while ( ++i < input.length )
	{
		/* Decode utf-16 surrogate pairs */
		x = input.charCodeAt ( i );
		y = i + 1 < input.length ? input.charCodeAt ( i + 1 ) : 0;
		if ( 0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF )
		{
			x = 0x10000 + ( ( x & 0x03FF ) << 10 ) + ( y & 0x03FF );
			i++;
		}

		/* Encode output as utf-8 */
		if ( x <= 0x7F )
			output += String.fromCharCode ( x );
		else if ( x <= 0x7FF )
			output += String.fromCharCode ( 0xC0 | ( ( x >>> 6 ) & 0x1F ),
			0x80 | ( x & 0x3F ) );
		else if ( x <= 0xFFFF )
			output += String.fromCharCode ( 0xE0 | ( ( x >>> 12 ) & 0x0F ),
			0x80 | ( ( x >>> 6 ) & 0x3F ),
			0x80 | ( x & 0x3F ) );
		else if ( x <= 0x1FFFFF )
			output += String.fromCharCode ( 0xF0 | ( ( x >>> 18 ) & 0x07 ),
			0x80 | ( ( x >>> 12 ) & 0x3F ),
			0x80 | ( ( x >>> 6 ) & 0x3F ),
			0x80 | ( x & 0x3F ) );
	}
	return output;
}

/**
 * Encode a string as utf-16
 *
 */
function str2rstr_utf16le ( input )
{
	var output = "";
	for ( var i = 0; i < input.length; i++ )
		output += String.fromCharCode ( input.charCodeAt ( i ) & 0xFF,
		( input.charCodeAt ( i ) >>> 8 ) & 0xFF );
	return output;
}

function str2rstr_utf16be ( input )
{
	var output = "";
	for ( var i = 0; i < input.length; i++ )
		output += String.fromCharCode ( ( input.charCodeAt ( i ) >>> 8 ) & 0xFF,
		input.charCodeAt ( i ) & 0xFF );
	return output;
}

/**
 * Convert a raw string to an array of big-endian words
 * Characters >255 have their high-byte silently ignored.
 *
 */
function rstr2binb ( input )
{
	var output = Array ( input.length >> 2 );
	for ( var i = 0; i < output.length; i++ )
		output[i] = 0;
	for ( var i = 0; i < input.length * 8; i += 8 )
		output[i >> 5] |= ( input.charCodeAt ( i / 8 ) & 0xFF ) << ( 24 - i % 32 );
	return output;
}

/**
 * Convert an array of big-endian words to a string
 *
 */
function binb2rstr ( input )
{
	var output = "";
	for ( var i = 0; i < input.length * 32; i += 8 )
		output += String.fromCharCode ( ( input[i >> 5] >>> ( 24 - i % 32 ) ) & 0xFF );
	return output;
}

/**
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 *
 */
function binb_sha1 ( x, len )
{
	/* append padding */
	x[len >> 5] |= 0x80 << ( 24 - len % 32 );
	x[ ( ( len + 64 >> 9 ) << 4 ) + 15] = len;

	var w = Array ( 80 );
	var a = 1732584193;
	var b = -271733879;
	var c = -1732584194;
	var d = 271733878;
	var e = -1009589776;

	for ( var i = 0; i < x.length; i += 16 )
	{
		var olda = a;
		var oldb = b;
		var oldc = c;
		var oldd = d;
		var olde = e;

		for ( var j = 0; j < 80; j++ )
		{
			if ( j < 16 ) w[j] = x[i + j];
			else w[j] = bit_rol ( w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1 );
			var t = safe_add ( safe_add ( bit_rol ( a, 5 ), sha1_ft ( j, b, c, d ) ),
				safe_add ( safe_add ( e, w[j] ), sha1_kt ( j ) ) );
			e = d;
			d = c;
			c = bit_rol ( b, 30 );
			b = a;
			a = t;
		}

		a = safe_add ( a, olda );
		b = safe_add ( b, oldb );
		c = safe_add ( c, oldc );
		d = safe_add ( d, oldd );
		e = safe_add ( e, olde );
	}
	return Array ( a, b, c, d, e );

}

/**
 * Perform the appropriate triplet combination function for the current
 * iteration
 *
 */
function sha1_ft ( t, b, c, d )
{
	if ( t < 20 ) return ( b & c ) | ( ( ~b ) & d );
	if ( t < 40 ) return b ^ c ^ d;
	if ( t < 60 ) return ( b & c ) | ( b & d ) | ( c & d );
	return b ^ c ^ d;
}

/**
 * Determine the appropriate additive constant for the current iteration
 *
 */
function sha1_kt ( t )
{
	return ( t < 20 ) ? 1518500249 : ( t < 40 ) ? 1859775393 :
	( t < 60 ) ? -1894007588 : -899497514;
}

/**
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 *
 */
function safe_add ( x, y )
{
	var lsw = ( x & 0xFFFF ) + ( y & 0xFFFF );
	var msw = ( x >> 16 ) + ( y >> 16 ) + ( lsw >> 16 );
	return ( msw << 16 ) | ( lsw & 0xFFFF );
}

/**
 * Bitwise rotate a 32-bit number to the left.
 *
 */
function bit_rol ( num, cnt )
{
	return ( num << cnt ) | ( num >>> ( 32 - cnt ) );
}

but now I need help converting this (HOP.JSP)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<%@ page import="sun.misc.BASE64Encoder, javax.crypto.*, javax.crypto.spec.*"%>
<%@ page import="java.util.*" %>

<%!
  private String getMerchantID() {
    return "merchantid";
  }

  private String getSharedSecret() {
    return "longsharedsectretstingwithlotsofhex;
  }

  private String getSerialNumber() {
    return "1234567890";
  }

  public String getPublicDigest(String customValues) throws Exception{
    String pub = getSharedSecret();
    BASE64Encoder encoder = new BASE64Encoder();
    Mac sha1Mac = Mac.getInstance("HmacSHA1");
    SecretKeySpec publicKeySpec = new SecretKeySpec(pub.getBytes(), "HmacSHA1");
    sha1Mac.init(publicKeySpec);
    byte[] publicBytes = sha1Mac.doFinal(customValues.getBytes());
    String publicDigest = encoder.encodeBuffer(publicBytes);
    return publicDigest.replaceAll("\n", "");
  }

  /**
   * @param map - Map containing fields that are to be signed.
   * Can only contain fields and values that should not be changed.
   * At the very minimum, map should contain 'amount', 'currency', and 'orderPage_transactionType'
   * if 'orderPage_transactionType' is 'subscription' or 'subscription_modify', the following are also required:
   * 'recurringSubscriptionInfo_amount', 'recurringSubscriptionInfo_numberOfPayments', 'recurringSubscriptionInfo_frequency',
   * 'recurringSubscriptionInfo_startDate', 'recurringSubscriptionInfo_automaticRenew'
   * if 'orderPage_transactionType' is 'subscription_modify' then 'paySubscriptionCreateReply_subscriptionID' is also required
   * @return html of hidden fields
   */
  public String insertSignature(Map map) {
    if (map == null) {
      return "";
    }
    try {
      map.put("merchantID", getMerchantID());
      map.put("orderPage_timestamp", String.valueOf(System.currentTimeMillis()));
      map.put("orderPage_version", "7");
      map.put("orderPage_serialNumber", getSerialNumber());
      Set keys = map.keySet();
      StringBuffer customFields = new StringBuffer();
      StringBuffer dataToSign = new StringBuffer();
      StringBuffer output = new StringBuffer();
      for (Iterator i = keys.iterator(); i.hasNext();) {
        String key = (String) i.next();
        customFields.append(key);
        dataToSign.append(key + "=" + String.valueOf(map.get(key)));
        if (i.hasNext()) {
          customFields.append(',');
          dataToSign.append(',');
        }

        output.append("<input type=\"hidden\" name=\"");
        output.append(key);
        output.append("\" value=\"");
        output.append(String.valueOf(map.get(key)));
        output.append("\">\n");
      }
      if(customFields.length() > 0) {
          dataToSign.append(',');
      }
      dataToSign.append("signedFieldsPublicSignature=");
      dataToSign.append(getPublicDigest(customFields.toString()).trim());
      output.append("<input type=\"hidden\" name=\"orderPage_signaturePublic\" value=\"" + getPublicDigest(dataToSign.toString()) + "\">\n");
      output.append("<input type=\"hidden\" name=\"orderPage_signedFields\" value=\"" + customFields.toString() + "\">\n");
      return output.toString();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  public String insertSignature(String amount, String currency) {
    try {
      if (amount == null) {
        amount = "0.00";
      }
      if (currency == null) {
        currency = "usd";
      }
      String time = String.valueOf(System.currentTimeMillis());
      String merchantID = getMerchantID();
      String data = merchantID + amount + currency + time;
      String serialNumber = getSerialNumber();
      StringBuffer sb = new StringBuffer();
      sb.append("<input type=\"hidden\" name=\"amount\" value=\"");
      sb.append(amount);
      sb.append("\">\n<input type=\"hidden\" name=\"currency\" value=\"");
      sb.append(currency);
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_timestamp\" value=\"");
      sb.append(time);
      sb.append("\">\n<input type=\"hidden\" name=\"merchantID\" value=\"");
      sb.append(merchantID);
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_signaturePublic\" value=\"");
      sb.append(getPublicDigest(data));
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_version\" value=\"7\">\n");
      sb.append("<input type=\"hidden\" name=\"orderPage_serialNumber\" value=\"");
      sb.append(serialNumber);
      sb.append("\">\n");
      return sb.toString();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  public String insertSignature(String amount, String currency, String orderPage_transactionType) {
    try {
      if (amount == null) {
        amount = "0.00";
      }
      if (currency == null) {
        currency = "usd";
      }
      String time = String.valueOf(System.currentTimeMillis());
      String merchantID = getMerchantID();
      String data = merchantID + amount + currency + time + orderPage_transactionType;
      String serialNumber = getSerialNumber();
      StringBuffer sb = new StringBuffer();
      sb.append("<input type=\"hidden\" name=\"amount\" value=\"");
      sb.append(amount);
       sb.append("\">\n<input type=\"hidden\" name=\"orderPage_transactionType\" value=\"");
      sb.append(orderPage_transactionType);
      sb.append("\">\n<input type=\"hidden\" name=\"currency\" value=\"");
      sb.append(currency);
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_timestamp\" value=\"");
      sb.append(time);
      sb.append("\">\n<input type=\"hidden\" name=\"merchantID\" value=\"");
      sb.append(merchantID);
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_signaturePublic\" value=\"");
      sb.append(getPublicDigest(data));
      sb.append("\">\n<input type=\"hidden\" name=\"orderPage_version\" value=\"7\">\n");
      sb.append("<input type=\"hidden\" name=\"orderPage_serialNumber\" value=\"");
      sb.append(serialNumber);
      sb.append("\">\n");
      return sb.toString();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  public String insertSubscriptionSignature(String subscriptionAmount, String subscriptionStartDate, String subscriptionFrequency,
                                            String subscriptionNumberOfPayments, String subscriptionAutomaticRenew) {
    if (subscriptionFrequency == null) {
      return "";
    }
    if (subscriptionAmount == null) {
      subscriptionAmount = "0.00";
    }
    if (subscriptionStartDate == null) {
      subscriptionStartDate = "00000000";
    }
    if (subscriptionNumberOfPayments == null) {
      subscriptionNumberOfPayments = "0";
    }
    if (subscriptionAutomaticRenew == null) {
      subscriptionAutomaticRenew = "true";
    }
    try {
      String data = subscriptionAmount + subscriptionStartDate + subscriptionFrequency + subscriptionNumberOfPayments + subscriptionAutomaticRenew;
      StringBuffer sb = new StringBuffer();
      sb.append("<input type=\"hidden\" name=\"recurringSubscriptionInfo_amount\" value=\"");
      sb.append(subscriptionAmount);
      sb.append("\">\n<input type=\"hidden\" name=\"recurringSubscriptionInfo_numberOfPayments\" value=\"");
      sb.append(subscriptionNumberOfPayments);
      sb.append("\">\n<input type=\"hidden\" name=\"recurringSubscriptionInfo_frequency\" value=\"");
      sb.append(subscriptionFrequency);
      sb.append("\">\n<input type=\"hidden\" name=\"recurringSubscriptionInfo_automaticRenew\" value=\"");
      sb.append(subscriptionAutomaticRenew);
      sb.append("\">\n<input type=\"hidden\" name=\"recurringSubscriptionInfo_startDate\" value=\"");
      sb.append(subscriptionStartDate);
      sb.append("\">\n<input type=\"hidden\" name=\"recurringSubscriptionInfo_signaturePublic\" value=\"");
      sb.append(getPublicDigest(data));
      sb.append("\">\n");
      return sb.toString();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  public String insertSubscriptionIDSignature(String subscriptionID) {
    if (subscriptionID == null) {
      return "";
    }
    try {
      StringBuffer sb = new StringBuffer();
      sb.append("<input type=\"hidden\" name=\"paySubscriptionCreateReply_subscriptionID\" value=\"");
      sb.append(subscriptionID);
      sb.append("\">\n<input type=\"hidden\" name=\"paySubscriptionCreateReply_subscriptionIDPublicSignature\" value=\"");
      sb.append(getPublicDigest(subscriptionID));
      sb.append("\">\n");
      return sb.toString();
    } catch (Exception e) {
      e.printStackTrace();
      return "";
    }
  }

  public boolean verifySignature(String data, String signature) {
    if (data == null || signature == null) {
      return false;
    }
    try {
      String pub = getSharedSecret();
      BASE64Encoder encoder = new BASE64Encoder();
      Mac sha1Mac = Mac.getInstance("HmacSHA1");
      SecretKeySpec publicKeySpec = new SecretKeySpec(pub.getBytes(), "HmacSHA1");
      sha1Mac.init(publicKeySpec);
      byte[] publicBytes = sha1Mac.doFinal(data.getBytes());
      String publicDigest = encoder.encodeBuffer(publicBytes);
      publicDigest = publicDigest.replaceAll("[\r\n\t]", "");
      return signature.equals(publicDigest);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }

  public boolean verifyTransactionSignature(Map map) {
    if (map == null) {
      return false;
    }
    String transactionSignature = (String) map.get("signedDataPublicSignature");
    if (transactionSignature == null) {
      return false;
    }
    String transactionSignatureFields = (String) map.get("signedFields");
    if (transactionSignatureFields == null) {
      return false;
    }
    StringTokenizer tokenizer = new StringTokenizer(transactionSignatureFields, ",", false);
    StringBuffer data = new StringBuffer();
    while (tokenizer.hasMoreTokens()) {
        String key = tokenizer.nextToken();
        data.append(key + "=" + map.get(key));
        data.append(',');
    }
    data.append("signedFieldsPublicSignature=");
    try{
        data.append(getPublicDigest(transactionSignatureFields).trim());
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
    return verifySignature(data.toString(), transactionSignature);
  }
%>

the first bits (get…) are easy to make into Servoy functions and the import of the sun and java stuff should be the SHA1 module I made above, it’s the rest that’s the problem :(
Any pointers as to what I can do (or a full translation :D ) would be GREATLY appreciated.
(If the HOP include module in any of the other languages would be better for someone, let me know…)
Thanks

Rafi

Why convert it when servoy can publish JSP by default? You just need to adjust the code a bit (see headless client docs) and put the file in the server/ROOT folder, then you can call it using the http plugin.

Hey Nicola,
you seem to be answering all my questions lately :D

ngervasi:
Why convert it when servoy can publish JSP by default? You just need to adjust the code a bit (see headless client docs) and put the file in the server/ROOT folder, then you can call it using the http plugin.

The way the payment processing is working currently is that a telephone operator at my client puts a customer order into a smart client form with a number of line items and then enters that customer’s credit card information and clicks a button to process transaction, when I then build up an POST in a Servoy method like

		// set up for doing an HTTP POST
		var poster = plugins.http.getPoster ( globals.protx_url );

		var didAddParam1 = poster.addParameter ( 'VPSProtocol', '2.22' );
		var didAddParam2 = poster.addParameter ( 'TxType', 'PAYMENT' );
		var didAddParam3 = poster.addParameter ( 'Vendor', 'myclient' );
		var didAddParam4 = poster.addParameter ( 'VendorTxCode', lv_txcode );
		var didAddParam5 = poster.addParameter ( 'Amount', lv_inv_total );
		var didAddParam6 = poster.addParameter ( 'Currency', lv_currency );
		var didAddParam7 = poster.addParameter ( 'Description', 'Transaction' );
		var didAddParam8 = poster.addParameter ( 'CardHolder', globals.bill_name );
		var didAddParam9 = poster.addParameter ( 'CardNumber', globals.cardnumber );
		if ( ( wp_cardstartdatemonth != null || wp_cardstartdatemonth != '' ) && ( wp_cardstartdateyear != null || wp_cardstartdateyear != '' ) )
		{
			var didAddParam10 = poster.addParameter ( 'StartDate', plugins.fmp.left ( wp_cardstartdatemonth, 2 ) + plugins.fmp.right ( wp_cardstartdateyear, 2 ) );
		}
		var didAddParam11 = poster.addParameter ( 'ExpiryDate', plugins.fmp.left ( wp_cardexpdatemonth, 2 ) + plugins.fmp.right ( wp_cardexpdateyear, 2 ) );
		var didAddParam12 = poster.addParameter ( 'IssueNumber', wp_cardissuenumber );
		var didAddParam13 = poster.addParameter ( 'CV2', wp_cardcvv );
		var didAddParam14 = poster.addParameter ( 'CardType', wp_card_type );
		var didAddParam15 = poster.addParameter ( 'BillingAddress', globals.bill_addr );
		var didAddParam16 = poster.addParameter ( 'BillingPostCode', globals.bill_pc );
		var didAddParam17 = poster.addParameter ( 'DeliveryAddress', globals.del_addr );
		var didAddParam18 = poster.addParameter ( 'DeliveryPostCode', globals.del_pc );
		var didAddParam19 = poster.addParameter ( 'CustomerName', globals.bill_name );
		var didAddParam20 = poster.addParameter ( 'ContactNumber', '' );
		var didAddParam21 = poster.addParameter ( 'ContactFax', '' );
		var didAddParam22 = poster.addParameter ( 'CustomerEMail', '' );
		var didAddParam23 = poster.addParameter ( 'ApplyAVSCV2', '0' );
		var httpCode = poster.doPost ( );

		globals.protx_received_text = poster.getPageData ( );

		handleProtxResult ( );

(this code would of course be different for CyberSource, but I think the type of data I’m sending would be similar …)
I had a quick look at the sample headless client solution (I couldn’t really find any proper docs on it [looked in Wiki]) and I can see that it can pick up and display Servoy data, but how would I ‘call’ HC to process a specific order (e.g. pass it orderID) and would I then have to create a line of HTML like

<tr>
<td>productid</td><td><input readonly type="text" name="productid" value="<%=servoy_hc.getDataProviderValue(null,"productid")%>"></td>
</tr>

for each bit of data I need to send?
Sorry to ask so much, but this sounds very promising, if only I knew how to use HC… :?
Thanks

Rafi

:)

Have a look at the JSP page I posted in the other thread about webclient login, you will see how to receive arguments and how to return results, you just need to tweak the above code a bit to return an array of strings instead of the html hidden input code but that should be easy.
Start looking at the jsp page I posted.

ngervasi:
:slight_smile:
Have a look at the JSP page I posted in the other thread about webclient login, you will see how to receive arguments and how to return results, you just need to tweak the above code a bit to return an array of strings instead of the html hidden input code but that should be easy.
Start looking at the jsp page I posted.

I have had another look and also found some docs on HC (the Servoy public APIs http://www.servoy.com/docs/public-api/6xx/index.html) and also managed to work out how to call the JPS page/HC with a parameter (orderID) from Servoy, but I can’t seem to see what call I need to make on the JSP page of HC to then find/load that orderID so I can then build up my parameters and send data to CyberSource??
I also assume that if I am using actual JSP pages, then something will always happen in a web browser, I can’t do all this with something like a

client = plugins.headlessclient.createClient('crm','login','pwd',null);

and have everything happen in the background??
Thanks

Rafi

Let’s continue out of here, I sent you a private message.