diff -rupN uc_eway/README.txt uc_eway_new/README.txt
--- uc_eway/README.txt	2009-06-18 17:32:41.000000000 +1000
+++ README.txt	2009-07-21 15:05:40.000000000 +1000
@@ -16,6 +16,12 @@ Installation
 
 - Create a folder in your modules directory called uc_eway and put the module's files in this directory
 
+- Use of recurring billing (ReBill) requires the NuSOAP library available at http://sourceforge.net/projects/nusoap/
+  - Install the NuSOAP library to the module's directory so that the directory structure looks like this:
+    uc_eway/nusoap
+    uc_eway/nusoap/lib
+    uc_eway/nusoap/lib/nusoap.php
+
 - Enable the module on the Modules admin page:
       Administer > Site building > Modules
 
diff -rupN uc_eway/uc_eway.install uc_eway_new/uc_eway.install
--- uc_eway/uc_eway.install	2009-06-18 17:32:41.000000000 +1000
+++ uc_eway.install	2009-07-21 15:29:27.000000000 +1000
@@ -12,6 +12,10 @@ function uc_eway_uninstall() {
   variable_del('uc_eway_test_mode');
   variable_del('uc_eway_test_approve_anyway');
   variable_del('uc_pg_eway_cc_txn_type');
+  variable_del('uc_eway_email_address');
+  variable_del('uc_eway_password');
+  variable_del('uc_eway_recurring_enabled');
+  variable_del('uc_eway_recurring_nusoap_path');
 }
 
 /**
diff -rupN uc_eway/uc_eway.module uc_eway_new/uc_eway.module
--- uc_eway/uc_eway.module	2009-07-06 11:48:37.000000000 +1000
+++ uc_eway.module	2009-07-21 15:51:53.000000000 +1000
@@ -15,17 +15,29 @@ require_once('uc_eway.ca.inc');
 
 // Define some variable_set defaults
 define('UC_EWAY_CUSTOMER_ID_DEFAULT', '87654321');
+define('UC_EWAY_EMAIL_ADDRESS_DEFAULT', 'test@eway.com.au');
+define('UC_EWAY_PASSWORD_DEFAULT', 'test123');
 define('UC_EWAY_MODE_DEFAULT', 'cvn_xml');
 define('UC_EWAY_LOGO_DEFAULT', 1);
 define('UC_EWAY_CHANGE_ORDER_STATUS_DEFAULT', 1);
 define('UC_EWAY_TEST_MODE_DEFAULT', 0);
 define('UC_EWAY_TEST_APPROVE_ANYWAY_DEFAULT', 0);
+define('UC_EWAY_RECURRING_ENABLED_DEFAULT', 0);
 
 // Define some variable_set defaults for block display
 define('UC_EWAY_BLOCK_POWERED_BY_SIZE_DEFAULT', 'large');
 define('UC_EWAY_BLOCK_POWERED_BY_COLOUR_DEFAULT', 'grey');
 
 /**
+ * Implementation of hook_init().
+ */
+function uc_eway_init() {
+  if (variable_get('uc_eway_recurring_enabled', UC_EWAY_RECURRING_ENABLED_DEFAULT)) {
+    require_once('uc_eway.recurring.inc');
+  }
+}
+
+/**
  * Implementation of hook_form_alter().
  */
 function uc_eway_form_alter(&$form, $form_state, $form_id) {
@@ -148,6 +160,18 @@ function uc_eway_settings_form() {
     '#default_value' => variable_get('uc_eway_customer_id', UC_EWAY_CUSTOMER_ID_DEFAULT),
     '#description' => t('Your eWAY customer ID. Provided to you by eWAY.'),
   );
+  $form['eway_settings']['uc_eway_email_address'] = array(
+    '#type' => 'textfield',
+    '#title' => t('eWAY email login'),
+    '#default_value' => variable_get('uc_eway_email_address', UC_EWAY_EMAIL_ADDRESS_DEFAULT),
+    '#description' => t('The email address you use to login to eWAY.'),
+  );
+  $form['eway_settings']['uc_eway_password'] = array(
+    '#type' => 'textfield',
+    '#title' => t('eWAY password'),
+    '#default_value' => variable_get('uc_eway_password', UC_EWAY_PASSWORD_DEFAULT),
+    '#description' => t('The password you use to login to eWAY.'),
+  );
   $form['eway_settings']['uc_eway_mode'] = array(
     '#type' => 'select',
     '#title' => t('eWAY mode'),
@@ -171,11 +195,40 @@ function uc_eway_settings_form() {
   );
   $form['eway_settings']['uc_eway_logo'] = array(
     '#type' => 'checkbox',
-    '#title' => t('Display eWay Logo?'),
-    '#description' => t('Displays the eWay logo when processing credit cards. This may be required for some people depending on your terms with eWay.'),
+    '#title' => t('Display eWAY Logo?'),
+    '#description' => t('Displays the eWay logo when processing credit cards. This may be required for some people depending on your terms with eWAY.'),
     '#default_value' => variable_get('uc_eway_logo', UC_EWAY_LOGO_DEFAULT),
   );
 
+  $form['eway_recurring'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Recurring Billing settings'),
+    '#collapsible' => true,
+    '#collapsed' => false
+  );
+  $form['eway_recurring']['uc_eway_recurring_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable recurring billing support'),
+    '#description' => t('Enables support for eWAY Rebill. Note that this requires the NuSOAP library to be correctly installed and configured. See README.txt in the uc_eway module directory for instructions.'),
+    '#default_value' => variable_get('uc_eway_recurring_enabled', UC_EWAY_RECURRING_ENABLED_DEFAULT),
+  );
+  if (variable_get('uc_eway_recurring_enabled', UC_EWAY_RECURRING_ENABLED_DEFAULT)) {
+    require_once('uc_eway.recurring.inc');
+    $form['eway_recurring']['uc_eway_recurring_nusoap_path'] = array(
+      '#type' => 'textfield',
+      '#title' => t('NuSOAP path'),
+      '#description' => t('The location where NuSOAP is installed. This should be a relative path to <em>nusoap.php</em>.'),
+      '#default_value' => uc_eway_recurring_nusoap_path(),
+    );
+    $found = file_exists(uc_eway_recurring_nusoap_path()) ? 'library' : 'library not';
+    $form['eway_recurring']['uc_eway_recurring_nusoap_status'] = array(
+      '#type' => 'markup',
+      '#value' => t('NuSOAP @found found', array('@found' => $found)),
+      '#prefix' => '<div>',
+      '#suffix' => '</div>',
+    );
+  }
+
   $form['eway_testing'] = array(
     '#type' => 'fieldset',
     '#title' => t('eWAY Testing settings'),
@@ -379,3 +432,18 @@ function uc_eway_process_request($xml, $
   }
 }
 
+/**
+ * Implementation of ubercart's hook_order().
+ */
+function uc_eway_order($op, &$arg1, $arg2) {
+  switch($op) {
+    case 'update':
+      if ($arg1->order_status == 'pending' && isset($arg1->data['eway_rebill_customer_id']) && $arg1->uid != 0) {
+        drupal_set_message("DEBUG: updating user " . $arg1->uid . " to have the eway rebill id of " . $arg1->data['eway_rebill_customer_id']);
+
+        $account = user_load(array('uid' => $arg1->uid));
+        $account = user_save($account, array('eway_rebill_customer_id' => $arg1->data['eway_rebill_customer_id']));
+      }
+      break;
+  }
+}
diff -rupN uc_eway/uc_eway.recurring.inc uc_eway_new/uc_eway.recurring.inc
--- uc_eway/uc_eway.recurring.inc	1970-01-01 10:00:00.000000000 +1000
+++ uc_eway.recurring.inc	2009-07-21 15:27:56.000000000 +1000
@@ -0,0 +1,396 @@
+<?php
+// $Id$
+
+/*******************************************************************************
+ * Hooks for uc_recurring
+ ******************************************************************************/
+
+// eWAY always requires an end date for recurring transactions. if we don't want an
+// end date, we'll just pass a date very far into the future.
+// TODO: eway creates a rebill entry for each transaction up until this date... which is
+// slow and silly. for now we just set this date a bit into the future
+define('UC_EWAY_RECURRING_VAST_END_DATE', date_format(date_create('+5 years'), 'd/m/Y'));
+
+/**
+ * Implements callback uc_recurring_[payment_method]_fee()
+ */
+function uc_recurring_eway_fee($order, &$fee) {
+  $account = user_load(array('uid' => $order->uid));
+
+  // is this user already a rebill customer?
+  if (!$account->eway_rebill_customer_id) {
+    watchdog('uc_eway_recurring', t('Creating new Rebill CustomerID for user ' . $account->uid));
+    $account = _uc_eway_recurring_create_rebill_customer($order);
+  }
+  else {
+    watchdog('uc_eway_recurring', t('Using existing Rebill CustomerID (' . $account->eway_rebill_customer_id . ') for user ' . $user->uid));
+  }
+
+  // how about now?
+  if (!$account->eway_rebill_customer_id) {
+    watchdog('uc_eway', t('Failed to create Rebill Customer'));
+    return FALSE;
+  }
+
+  // create a rebill event
+  $result = _uc_eway_recurring_create_rebill_event($order, $fee, $account);
+
+  if ($result['error']) {
+    watchdog('uc_eway_recurring', t('Failed to create Rebill Event: ' . $result['ErrorDetails']));
+    return FALSE;
+  }
+  else {
+    watchdog('uc_eway_recurring', t('Created Rebill Event: ' . $result['RebillID']));
+    $fee->fee_handler = 'eway';
+    $fee->data = array('rebill_id' => $result['RebillID']);   
+
+    return TRUE;
+  }
+}
+
+/**
+ * Implements callback uc_recurring_[fee_handler]_renew()
+ */
+function uc_recurring_eway_renew($order, $fee) {
+  $account = user_load(array('uid' => $order->uid));
+
+  $result = _uc_eway_recurring_query_rebill_transactions($fee, $account);
+
+  watchdog('uc_eway_recurring', t('QueryTransactionResponse: ' . var_export($result, TRUE)));
+
+  // get all transactions, test if this fee went through
+  if (count($result['Successful']['QueryTransactionsResult'])) {
+    watchdog('uc_eway_recurring', t('Renew charged for fee: ' . var_export($fee, TRUE) . ', Transaction status is SUCCESSFUL: ' . var_export($result['Successful'], TRUE)));
+    return TRUE;
+  }
+  elseif (count($result['Failed']['QueryTransactionsResult'])) {
+    watchdog('uc_eway_recurring', t('Renew failed for fee: ' . var_export($fee, TRUE) . ', Transaction status is FAILED: ' . var_export($result['Failed'], TRUE)));
+    return FALSE;
+  }
+  else {
+    // something went very wrong
+    return FALSE;
+  }
+}
+
+/**
+ * Implements *optional* callback uc_recurring_[fee_handler]_renew_pending()
+ */
+function uc_recurring_eway_renew_pending($fee) {
+  $account = user_load(array('uid' => $fee['uid']));
+  $result = _uc_eway_recurring_query_rebill_transactions($fee, $account);
+
+  watchdog('uc_eway_recurring', 'uc_recurring_eway_renew_fee(): ' . var_export($result, TRUE));
+
+  if (isset($result['Future']['QueryTransactionsResult']['rebillTransaction'])) {
+    watchdog('uc_eway_recurring', 'FUTURE!');
+    return TRUE;
+  }
+  elseif (isset($result['Pending']['QueryTransactionsResult']['rebillTransaction'])) {
+    watchdog('uc_eway_recurring', 'PENDING!');
+    return TRUE;
+  }
+  else {
+    watchdog('uc_eway_recurring', 'returning FALSE!');
+    return FALSE;
+  }
+}
+
+/**
+ * Implements (*optional*) callback uc_recurring_[fee_handler]_fee_ops()
+ */
+function uc_recurring_eway_fee_ops($context, $fee) {
+  $ops = array();
+  switch ($context) {
+     case 'fee_admin':
+       $ops[] = l('delete', 'admin/store/orders/recurring/'. $fee['rfid'] .'/delete');
+       break;
+     case 'user':
+       // add links to operations that end users should be able to perform on their own fee
+       break;
+  }
+  return $ops;
+}
+
+/**
+ * Implements hook_recurring_api().
+ */
+function uc_eway_recurring_api($op, $id) {
+  switch ($op) {
+    case 'delete':
+      $fee = db_fetch_array(db_query("SELECT * FROM {uc_recurring_users} WHERE rfid = %d", $id));
+      $fee['data'] = unserialize($fee['data']);
+      $account = user_load(array('uid' => $fee['uid']));
+      _uc_eway_recurring_delete_rebill_event($fee, $account);
+      break;
+  }
+}
+
+/*******************************************************************************
+ * Module functions
+ ******************************************************************************/
+
+/**
+ * Returns the path of the NuSOAP library
+ */
+function uc_eway_recurring_nusoap_path() {
+  return variable_get('uc_eway_recurring_nusoap_path', drupal_get_path('module', 'uc_eway') . '/nusoap/lib/nusoap.php');
+}
+
+/**
+ * The actual SOAP call using the NuSOAP library
+ */
+function _uc_eway_recurring_soap_call($operation, $params) {
+  $endpoint = variable_get('uc_eway_test_mode', UC_EWAY_TEST_MODE_DEFAULT) ? 'https://www.eway.com.au/gateway/rebill/test/manageRebill_test.asmx?WSDL' : 'https://www.eway.com.au/gateway/rebill/manageRebill.asmx?WSDL';
+  $namespace = 'http://www.eway.com.au/gateway/rebill/manageRebill';
+  $header = '<eWAYHeader xmlns="http://www.eway.com.au/gateway/rebill/manageRebill"> 
+    <eWAYCustomerID>' . variable_get('uc_eway_customer_id', UC_EWAY_CUSTOMER_ID_DEFAULT) . '</eWAYCustomerID> 
+    <Username>' . variable_get('uc_eway_email_address', UC_EWAY_EMAIL_ADDRESS_DEFAULT)  . '</Username> 
+    <Password>' . variable_get('uc_eway_password', UC_EWAY_PASSWORD_DEFAULT)  . '</Password> 
+    </eWAYHeader>'; // TODO: replace with soapval
+
+  if (@include_once(realpath(uc_eway_recurring_nusoap_path()))) {
+    $client = new nusoap_client($endpoint, TRUE);
+    $client->response_timeout = 50;
+    $result = $client->call($operation, $params, $namespace, '', $header);
+  } else {
+    $result = FALSE;
+  }
+
+  //if (variable_get('uc_eway_test_mode', UC_EWAY_TEST_MODE_DEFAULT)) {
+    watchdog('uc_eway_recurring', 'SOAP Call (' . $operation . ') request: ' . var_export($params, TRUE) . ', response: ' . var_export($result, TRUE));
+  //  watchdog('uc_eway_recurring', 'NuSOAP client: ' . var_export($client, TRUE));
+  //}
+
+  return $result;
+}
+
+/**
+ * DEBUG TIME FUNCTION
+ */
+function _time($type = 'none') {
+  return time();
+  switch($type) {
+    case 'uc_recurring_fee':
+      $hour = 7;
+      $minute = 0;
+      $second = 0;
+      $month = 6;
+      $day = 27;
+      $year = 2009;
+      break;
+    case 'uc_recurring_renew':
+      $hour = 7;
+      $minute = 1;
+      $second = 0;
+      $month = 6;
+      $day = 27;
+      $year = 2009;
+      break;
+    default:
+      return time();
+  }
+
+  $time = mktime($hour, $minute, $second, $month, $day, $year);
+
+  return $time;
+}
+
+/**
+ * Create Rebill Customer
+ */
+function _uc_eway_recurring_create_rebill_customer($order) {
+  $account = user_load(array('uid' => $order->uid));
+
+  $country = uc_get_country_data(array('country_id' => $order->billing_country));
+
+  $data = array(
+    'ewayCustomerID' => variable_get('uc_eway_customer_id', UC_EWAY_CUSTOMER_ID_DEFAULT),
+    'customerTitle' => '',
+    'customerFirstName' => (string) $order->billing_first_name,
+    'customerLastName' => (string) $order->billing_last_name,
+    'customerAddress' => (string) $order->billing_street1 . ' ' . $order->billing_street2,
+    'customerSuburb' => (string) $order->billing_city,
+    'customerState' => (string) uc_get_zone_code($order->billing_zone),
+    'customerCompany' => (string) $order->billing_company,
+    'customerPostCode' => (string) $order->billing_postal_code,
+    'customerCountry' => (string) $country[0]['country_name'],
+    'customerEmail' => (string) $order->primary_email,
+    'customerFax' => '',
+    'customerPhone1' => '',
+    'customerPhone2' => '',
+    'customerRef' => $order->uid,
+    'customerJobDesc' => '',
+    'customerComments' => '',
+    'customerURL' => '',
+  );
+
+  $response = _uc_eway_recurring_soap_call('CreateRebillCustomer', $data);
+
+  if ($response['CreateRebillCustomerResult']['Result'] == 'Success') {
+    $account = user_save($account, array(
+      'eway_rebill_customer_id' => $response['CreateRebillCustomerResult']['RebillCustomerID'],
+    ));
+  }
+
+  return $account;
+}
+
+/**
+ * Update Rebill Customer
+ */
+function _uc_eway_recurring_update_rebill_customer() {
+}
+
+/**
+ * Query Rebill Customer
+ */
+function _uc_eway_recurring_query_rebill_customer() {
+}
+
+/**
+ * Delete Rebill Customer
+ */
+function _uc_eway_recurring_delete_rebill_customer() {
+}
+
+/**
+ * Create Rebill Event
+ */
+function _uc_eway_recurring_create_rebill_event($order, $fee, $account) {
+  // create invoice description
+  $description = '';
+  if (is_array($order->products)) {
+    foreach ($order->products as $product) {
+      if (!empty($description)) {
+        $description .= ' / ';
+      }
+      $description .= $product->qty . 'x ' . $product->title . ' ';
+      if (is_array($product->data['attributes'])) {
+        foreach ($product->data['attributes'] as $key => $value) {
+          $description .= ', '. $key .': '. $value;
+        }
+      }
+    }
+  }
+
+  $cc_name = strlen($order->payment_details['cc_name']) ? $order->payment_details['cc_name'] : $order->billing_first_name . ' ' . $order->billing_last_name;
+
+  // get data from uc_recurring -> eway rebill format
+  $initial_charge = split(' ', $fee->initial_charge);
+  if ((int)$initial_charge[0] === 0) {
+    $init_fee = (int)$fee->fee_amount * 100;
+  }
+  else {
+    $init_fee = 0;
+  }
+  $regular_interval = split(' ', $fee->regular_interval);
+  $start_timestamp = strtotime('+' . $fee->regular_interval);
+  switch($regular_interval[1]) {
+    case 'days': $interval_type = 1; break;
+    case 'weeks': $interval_type = 2; break;
+    case 'months': $interval_type = 3; break;
+    case 'years': $interval_type = 4; break;
+  }
+  if ($fee->number_intervals) {
+    $end_date = date('d/m/Y', strtotime('+' . $regular_interval[0] * $fee->number_intervals . ' ' . $regular_interval[1]));
+  }
+  else {
+    $end_date = UC_EWAY_RECURRING_VAST_END_DATE;
+  }
+
+  $data = array(
+    'RebillCustomerID' => $account->eway_rebill_customer_id,
+    'RebillInvRef' => $order->order_id,
+    'RebillInvDes' => substr($description, 0, 10000),
+    'RebillCCName' => $cc_name,
+    'RebillCCNumber' => $order->payment_details['cc_number'],
+    'RebillCCExpMonth' => $order->payment_details['cc_exp_month'],
+    'RebillCCExpYear' => $order->payment_details['cc_exp_year'],
+    'RebillInitAmt' => $init_fee,
+    'RebillInitDate' => date('d/m/Y'),
+    'RebillRecurAmt' => (int)$fee->fee_amount * 100,
+    'RebillStartDate' => date('d/m/Y', $start_timestamp),
+    'RebillInterval' => $regular_interval[0],
+    'RebillIntervalType' => $interval_type,
+    'RebillEndDate' => $end_date,
+  );
+
+  $response = _uc_eway_recurring_soap_call('CreateRebillEvent', $data);
+
+  if ($response['CreateRebillEventResult']['Result'] == 'Success') {
+    return array(
+      'error' => 0,
+      'RebillID' => $response['CreateRebillEventResult']['RebillID'],
+    );
+  }
+  else {
+    return array(
+      'error' => 1,
+      'ErrorDetails' => $response['CreateRebillEventResult']['ErrorDetails'],
+    );
+  }
+}
+
+/**
+ * Update Rebill Event
+ */
+function _uc_eway_recurring_update_rebill_event() {
+}
+
+/**
+ * Query Rebill Event
+ */
+function _uc_eway_recurring_query_rebill_event() {
+}
+
+/**
+ * Delete Rebill Event
+ */
+function _uc_eway_recurring_delete_rebill_event($fee, $account) {
+  $data = array(
+    'RebillCustomerID' => $account->eway_rebill_customer_id,
+    'RebillID' => $fee['data']['rebill_id'],
+  );
+
+  $response = _uc_eway_recurring_soap_call('DeleteRebillEvent', $data);
+
+  if ($response['RebillEventDetails']['Result'] == 'Success') {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Query Next Rebill Transaction
+ */
+function _uc_eway_recurring_query_next_rebill_transaction() {
+}
+
+/**
+ * Query Rebill Transactions
+ */
+function _uc_eway_recurring_query_rebill_transactions($fee, $account) {
+  $date = date('Y-m-d', $fee['next_charge']);
+
+  // eWAY doco says status is optional, and this should return them all
+  // this doesn't appear to be the case. so we make 4 requests to get them
+  // all and we return an array of them all.
+  $statuses = array('Future', 'Pending', 'Successful', 'Failed');
+
+  foreach ($statuses as $status) {
+    $data = array(
+      'RebillCustomerID' => $account->eway_rebill_customer_id,
+      'RebillID' => $fee['data']['rebill_id'],
+      'startDate' => $date,
+      'endDate' => $date,
+      'status' => $status
+    );
+
+    $response[$status] = _uc_eway_recurring_soap_call('QueryTransactions', $data);
+  }
+
+  return $response;
+}
