diff -U5 -r uc_paymentexpress.orig/uc_dps_pxpost.module uc_paymentexpress/uc_dps_pxpost.module
--- uc_paymentexpress.orig/uc_dps_pxpost.module	2009-12-10 16:27:39.000000000 +1300
+++ uc_paymentexpress/uc_dps_pxpost.module	2010-07-19 14:43:25.000000000 +1200
@@ -3,51 +3,20 @@
 
 /**
  * @file
  * Ubercart DPS PXPost module provides Payment Express PXAccess service from Direct Payment Solutions
  *
- * Developed by Patrick Harris <patrickpaganini@gmail.com>
- *
- * Updates by Chris Burgess <chris@giantrobot.co.nz>
+ * @author Patrick Harris <patrickpaganini@gmail.com>
+ * @author Chris Burgess <chris@giantrobot.co.nz>
+ * @author Neil Bertram <neil@catalyst.net.nz
  *
  */
 
 
 /*******************************************************************************
  * Callback Functions, Forms, and Tables
  ******************************************************************************/
-/**
- * Implementation of hook_menu().
- */
-function uc_dps_pxpost_menu() {
-  if ($may_cache) {
-    // Callback functions for Website Payments Standard.
-    $items[] = array(
-      'path' => 'uc_dps_pxpost_preliminary',
-      'title' => t('DPS PxPay'),
-      'callback' => 'uc_dps_pxpost_preliminary',
-      'access' => TRUE,
-      'type' => MENU_CALLBACK,
-    );
-    $items[] = array(
-      'path' => 'uc_dps_pxpost/complete',
-      'title' => t('DPS PxPay payment complete'),
-      'callback' => 'uc_dps_pxpost_complete',
-      'access' => TRUE,
-      'type' => MENU_CALLBACK,
-    );
-    $items[] = array(
-      'path' => 'uc_dps_pxpost/cancel',
-      'title' => t('DPS PxPay payment cancelled'),
-      'callback' => 'uc_dps_pxpost_cancel',
-      'access' => TRUE,
-      'type' => MENU_CALLBACK,
-    );
-  }
-
-  return $items;
-}
 
 /**
  * Implementation of hook_perm().
  */
 function uc_dps_pxpost_perm() {
@@ -62,19 +31,20 @@
 
 /**
  * Implementation of hook_payment_gateway().
  */
 function uc_dps_pxpost_payment_gateway() {
-  $gateways[] = array(
-    'id' => 'uc_dps_pxpost',
-    'title' => t('DPS PxPost'),
-    'description' => t('Process credit card payments using DPS on your site.'),
-    'settings' => 'uc_dps_pxpost_settings_form',
-    'credit' => 'uc_dps_pxpost_charge',
+  return array(
+    array(
+      'id' => 'uc_dps_pxpost',
+      'title' => t('DPS PxPost'),
+      'description' => t('Process credit card payments using DPS on your site.'),
+      'settings' => 'uc_dps_pxpost_settings_form',
+      'credit' => 'uc_dps_pxpost_charge',
+      'credit_txn_types' => array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_PRIOR_AUTH_CAPTURE, UC_CREDIT_AUTH_CAPTURE, UC_CREDIT_CREDIT)
+    )
   );
-
-  return $gateways;
 }
 
 // Settings for DPS PxPost on the Payment gateways form.
 function uc_dps_pxpost_settings_form() {
   $form['uc_dps_pxpost']['uc_dps_pxpost_username'] = array(
@@ -145,139 +115,133 @@
 Track2 	              Extracted from Track2 of credit card.
 
 */
 // Process a credit card payment through DPS PxPost.
 function uc_dps_pxpost_charge($order_id, $amount, $data){
-  if (!function_exists('curl_init')) {
-    drupal_set_message(t('The DPS Payment Express service requires cURL.  Please talk to your system administrator to get this configured.'));
-    return array('success' => FALSE);
-  }
-
   global $user, $response;
   $order = uc_order_load($order_id);
-  
+
   $username = variable_get('uc_dps_pxpost_username', '');
   $password = variable_get('uc_dps_pxpost_password', '');
-  
+
   $inputcurrency = variable_get('uc_dps_pxpost_currency', 'NZD');
   $cardholdername = $order->billing_first_name.' '.$order->billing_last_name;
   $cardnumber = $order->payment_details['cc_number'];
+  $cvv = null;
+  if (!empty($order->payment_details['cc_cvv'])) {
+    $cvv = $order->payment_details['cc_cvv'];
+  }
   // Convert Date Format to 0406
-  $month = $order->payment_details['cc_exp_month'];
-  if ($month < 10 ) {$month = '0'.$month;}
+  $month = str_pad($order->payment_details['cc_exp_month'], 2, '0', STR_PAD_LEFT);
   $year = substr($order->payment_details['cc_exp_year'], 2, 2);
-  $dateexpiry = $month.$year;
-  
-  $txntype = 'Purchase';
+  $dateexpiry = sprintf('%02d%02d', $order->payment_details['cc_exp_month'], $year);
+
+  // Map Ubercart transaction types to DPS ones
+  $txntype_map = array(
+    UC_CREDIT_AUTH_CAPTURE => 'Purchase',
+    UC_CREDIT_AUTH_ONLY => 'Auth',
+    UC_CREDIT_PRIOR_AUTH_CAPTURE => 'Complete',
+    UC_CREDIT_CREDIT => 'Refund'
+  );
+  $txntype = $txntype_map[$data['txn_type']];
+
   $merchant_reference = $order->order_id;
-    
-  $cmdDoTxnTransaction .= '<Txn>';
-  $cmdDoTxnTransaction .= '<PostUsername>'.$username.'</PostUsername>';
-  $cmdDoTxnTransaction .= '<PostPassword>'.$password.'</PostPassword>';
-  $cmdDoTxnTransaction .= '<Amount>'.$amount.'</Amount>';
-  $cmdDoTxnTransaction .= '<InputCurrency>'.$inputcurrency.'</InputCurrency>';
-  $cmdDoTxnTransaction .= '<CardHolderName>'.$cardholdername.'</CardHolderName>';
-  $cmdDoTxnTransaction .= '<CardNumber>'.$cardnumber.'</CardNumber>';
-  $cmdDoTxnTransaction .= '<DateExpiry>'.$dateexpiry.'</DateExpiry>';
-  $cmdDoTxnTransaction .= '<TxnType>'.$txntype.'</TxnType>';
-  $cmdDoTxnTransaction .= '<MerchantReference>'.$merchant_reference.'</MerchantReference>';
-  $cmdDoTxnTransaction .= '</Txn>';
-  
-  $URL = "www.paymentexpress.com/pxpost.aspx";
- 
-  $ch = curl_init(); 
-  curl_setopt($ch, CURLOPT_URL,"https://".$URL);
-  curl_setopt($ch, CURLOPT_POST, 1);
-  curl_setopt($ch, CURLOPT_POSTFIELDS,$cmdDoTxnTransaction);
-  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-  //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //Needs to be included if no *.crt is available to verify SSL certificates
-  curl_setopt($ch,CURLOPT_SSLVERSION,3);	
-  $result = curl_exec ($ch); 
-  curl_close ($ch);
-  
-  $params = _uc_dps_pxpost_parse_xml($result);
-  
-  $success = $params['TXN']['SUCCESS'];
-    
-  $MerchantReference = $params['TXN'][$success]['MERCHANTREFERENCE'];
-  $CardHolderName	= $params['TXN'][$success]['CARDHOLDERNAME'];
-  $AuthCode = $params['TXN'][$success]['AUTHCODE'];
-  $Amount	= $params['TXN'][$success]['AMOUNT'];
-  $CurrencyName = $params['TXN'][$success]['CURRENCYNAME'];
-  $TxnType = $params['TXN'][$success]['TXNTYPE'];
-  $CardNumber	= $params['TXN'][$success]['CARDNUMBER'];
-  $DateExpiry	= $params['TXN'][$success]['DATEEXPIRY'];
-  $CardHolderResponseText	= $params['TXN'][$success]['CARDHOLDERRESPONSETEXT'];
-  $CardHolderResponseDescription = $params['TXN'][$success]['CARDHOLDERRESPONSEDESCRIPTION'];
-  $MerchantResponseText = $params['TXN'][$success]['MERCHANTRESPONSETEXT'];
-  $DPSTxnRef = $params['TXN'][$success]['DPSTXNREF'];
-
-  // @TODO log transactions to watchdog also (?)
-  if ($success != '1') {
-    $message = t('Credit card declined: !amount', array('!amount' => uc_currency_format($amount)));
-    $result = array(
+
+  $xml = new XMLWriter();
+  $xml->openMemory();
+  $xml->startElement('Txn');
+  $xml->writeElement('PostUsername', $username);
+  $xml->writeElement('PostPassword', $password);
+  $xml->writeElement('Amount', number_format($amount, 2));
+  if ($txntype == 'Purchase' || $txntype == 'Auth') {
+    $xml->writeElement('InputCurrency', $inputcurrency);
+    $xml->writeElement('CardHolderName', $cardholdername);
+    $xml->writeElement('CardNumber', $cardnumber);
+    if ($cvv) {
+      $xml->writeElement('Cvc2', $cvv);
+    }
+    $xml->writeElement('DateExpiry', $dateexpiry);
+    $xml->writeElement('MerchantReference', $merchant_reference);
+  }
+  $xml->writeElement('TxnType', $txntype);
+
+  if ($txntype == 'Refund') {
+    // Need to supply the previous DpsTxnId
+    $xml->writeElement('DpsTxnRef', $data['txn_id']);
+  }
+  else if ($txntype == 'Complete') {
+    // Need to supply the previous DpsTxnId
+    $xml->writeElement('DpsTxnRef', $data['auth_id']);
+  }
+  $xml->endElement();
+  $cmdDoTxnTransaction = $xml->outputMemory();
+
+  $URL = 'www.paymentexpress.com/pxpost.aspx';
+
+  $result = drupal_http_request('https://'.$URL, array('Content-type' =>  'application/xml'), 'POST', $cmdDoTxnTransaction);
+  if (!empty($result->error)) {
+    return array(
       'success' => FALSE,
-      'comment' => t('Credit card payment declined: !text', array('!text' => $MerchantResponseText)),
-      'message' => t('Credit card payment declined: !text', array('!text' => $MerchantResponseText)),
-      'uid' => $user->uid,
+      'comment' => t('Failed to process credit card payment (HTTP error: @error)', array('@error' => $result->error)),
+      'message' => t('Failed to process credit card payment (HTTP error: @error)', array('@error' => $result->error)),
+      'uid' => $user->uid
     );
   }
-  else {
-    $message = t('Credit card charged: !amount', array('!amount' => uc_currency_format($Amount)));
-    $result = array(
-      'success' => TRUE,
-      'comment' => t('Credit card payment processed successfully.<br/>Approval code: !code', array('!code' => $TxnType)),
-      'message' => t('Credit card payment processed successfully.<br/>Approval code: !code', array('!code' => $TxnType)),
-      'uid' => $user->uid,
+
+  try {
+    $response = new SimpleXMLElement($result->data);
+  }
+  catch (Exception $e) {
+    return array(
+      'success' => FALSE,
+      'comment' => t('Failed to parse DPS XML: @xml, error: @error)', array('@error' => $e->getMessage(), '@xml' => $result->data)),
+      'message' => t('Failed to parse DPS XML: @xml, error: @error)', array('@error' => $e->getMessage(), '@xml' => $result->data)),
+      'uid' => $user->uid
     );
   }
-  uc_order_comment_save($order_id, $user->uid, $message . t('<br />Response code: !code - !text', array('!code' => $TxnType, '!text' => $MerchantResponseText)), 'admin');
 
-  return $result;
+  $txn = $response->Transaction[0];
+  $success = (bool)(int)$response->Success;
 
-}
-
-/**
- * @TODO does this need to be just an empty function?
- */
-function uc_dps_pxpost_complete() {
-  
-}
+  $MerchantReference = (string)$txn->MerchantReference;
+  $CardHolderName	= (string)$txn->CardHolderName;
+  $AuthCode = (string)$txn->AuthCode;
+  $Amount	= (string)$txn->Amount;
+  $CurrencyName = (string)$txn->CurrencyName;
+  $TxnType = (string)$txn->TxnType;
+  $CardNumber	= (string)$txn->CardNumber;
+  $DateExpiry	= (string)$txn->DateExpiry;
+  $CardHolderResponseText	= (string)$txn->CardHolderResponseText;
+  $CardHolderResponseDescription = (string)$txn->CardHolderResponseDescription;
+  $MerchantResponseText = (string)$txn->MerchantResponseText;
+  $DPSTxnRef = (string)$txn->DpsTxnRef;
+
+  $message = t('Credit card transaction (@type) @acceptdecline: @text. TxnRef: @txnref', array('@type' => $TxnType, '@acceptdecline' => $success ? t('accepted') : t('declined'), '@text' => $MerchantResponseText, '@txnref' => $DPSTxnRef));
+  $result = array(
+    'success' => $success,
+    'comment' => $message,
+    'message' => $message,
+    'data' => array(
+      'module' => 'uc_dps_pxpost',
+      'txn_type' => $TxnType,
+      'txn_id' => $DPSTxnRef
+    ),
+    'uid' => $user->uid
+  );
 
-/**
- * @TODO consider other methods of constructing $params result here which don't use eval()
- * 
- */
-function _uc_dps_pxpost_parse_xml($data) {
-  $xml_parser = xml_parser_create();
-  xml_parse_into_struct($xml_parser, $data, $vals, $index);
-  xml_parser_free($xml_parser);
-    
-  $params = array();
-  $level = array();
-  foreach ($vals as $xml_elem) {
-    if ($xml_elem['type'] == 'open') {
-      if (array_key_exists('attributes',$xml_elem)) {
-        list($level[$xml_elem['level']],$extra) = array_values($xml_elem['attributes']);
-      } 
-      else {
-        $level[$xml_elem['level']] = $xml_elem['tag'];
-      }
-    }
-    if ($xml_elem['type'] == 'complete') {
-      $start_level = 1;
-      $php_stmt = '$params';
-            
-      while($start_level < $xml_elem['level']) {
-        $php_stmt .= '[$level['.$start_level.']]';
-        $start_level++;
-      }
-      $php_stmt .= '[$xml_elem[\'tag\']] = $xml_elem[\'value\'];';
-      eval($php_stmt);
-    }
+  if ($TxnType == 'Auth') {
+    // Don't log as a payment yet
+    $result['log_payment'] = FALSE;
+    uc_credit_log_authorization($order_id, $DPSTxnRef, $Amount);
+  }
+  else if ($TxnType == 'Complete') {
+    // Note that the completion has a different DPS TxnRef than the original Auth
+    uc_credit_log_prior_auth_capture($order_id, $data['auth_id']);
   }
-  return $params;
+
+  uc_order_comment_save($order_id, $user->uid, $message, 'admin');
+  return $result;
 }
 
 /** 
  * Returns an array of possible currency codes. This is now duplicated (and
  * improved upon) in _uc_dps_pxpay_currency_array(), and should prob be shared
