Index: file.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ecommerce/file/Attic/file.module,v
retrieving revision 1.37.2.7.2.1.2.16
diff -u -r1.37.2.7.2.1.2.16 file.module
--- file.module	3 Aug 2007 02:48:35 -0000	1.37.2.7.2.1.2.16
+++ file.module	24 May 2009 19:13:57 -0000
@@ -31,14 +31,14 @@
   if ($may_cache) {
     if ($user->uid) {
       $items[] = array(
-        'path' => 'ec_file/autocomplete', 
+        'path' => 'ec_file/autocomplete',
         'title' => t('File autocomplete'),
         'callback' => 'ec_file_autocomplete',
-        'access' => $access, 
+        'access' => $access,
         'type' => MENU_CALLBACK,
       );
       $items[] = array(
-        'path' => 'store/myfiles/'. $user->uid, 
+        'path' => 'store/myfiles/'. $user->uid,
         'title' => t('My files'),
         'callback' => 'file_my_overview',
         'callback arguments' => array($user->uid),
@@ -46,18 +46,18 @@
         'type' => MENU_NORMAL_ITEM,
       );
       $items[] = array(
-        'path' => 'store/myfiles/'. $user->uid .'/download', 
+        'path' => 'store/myfiles/'. $user->uid .'/download',
         'title' => t('Download'),
-        'callback' => 'ec_product_download', 
+        'callback' => 'ec_product_download',
         'access' => user_access('access content'),
         'type' => MENU_CALLBACK,
       );
     }
     $items[] = array(
-      'path' => 'admin/store/products/files', 
+      'path' => 'admin/store/products/files',
       'title' => t('Product file quicklist'),
-      'callback' => 'file_quicklist', 
-      'access' => $access, 
+      'callback' => 'file_quicklist',
+      'access' => $access,
       'type' => MENU_CALLBACK,
     );
     $items[] = array(
@@ -74,9 +74,9 @@
   else {
     if ($access) {
       $items[] = array(
-        'path' => 'store/myfiles/', 
+        'path' => 'store/myfiles/',
         'title' => t('User Files'),
-        'callback' => 'file_my_overview', 
+        'callback' => 'file_my_overview',
         'access' => TRUE,
         'type' => MENU_LOCAL_TASK,
       );
@@ -152,6 +152,12 @@
       return array('file' => t('File download product'));
       break;
 
+    //case 'subproduct_types':
+    //  return array('file');
+
+    //case 'cart add item':
+    //  return subproducts_cart_set_subproduct_variation($node, $a3);
+
     case 'attributes':
       return array('in_stock');
       break;
@@ -185,8 +191,7 @@
       );
       $form['f_settings']['edit_size'] = array('#type' => 'value', '#value' => array());
       // Pass some info to ec_recurring.
-      $form['recurring']['sid'] = array( '#allow_renewals' => FALSE, );
-
+      //$form['recurring']['sid'] = array( '#allow_renewals' => FALSE, );
       return $form;
 
      /* Similar to node_load */
@@ -242,13 +247,20 @@
  * Implementation of hook_settings().
  */
 function file_ec_settings() {
-  drupal_set_title(t('Ecommerce file download settings (%revision)', array('%revision' => '$Revision: 1.37.2.7.2.1.2.16 $')));
+
+  drupal_set_title(t('Ecommerce file download settings'));
 
   if (!isset($_POST['op'])) {
     $file_path = variable_get('ec_file_directory_path', 'files');
     file_check_directory($file_path, 0, 'ec_file_directory_path');
   }
-  $form['ec_file_directory_path'] = array(
+  $form['main'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('Main settings'),
+  );
+  $form['main']['ec_file_directory_path'] = array(
     '#type' => 'textfield',
     '#title' => t('File path for products'),
     '#default_value' => variable_get('ec_file_directory_path', 'files'),
@@ -257,9 +269,11 @@
     '#description' => t('A file system path where the product files are stored. This directory has to exist and be writable by Drupal. This directory should not be accessible over the web. Changing this location after the site has been in use will cause problems so only change this setting on an existing site if you know what you are doing.'),
     '#validate' => array('file_directory_validate' => array()),
   );
+  $cutofftime = variable_get('file_expiry_setting','');
+  if (!$cutofftime) {
   $slist = array_merge(array(0 => '--'), ec_recurring_get_list(FALSE));
-  // TODO Implement the code to use this feature. 
-  $form['ec_file_default_schedule'] = array(
+  // TODO Implement the code to use this feature.
+  $form['main']['ec_file_default_schedule'] = array(
     '#type' => 'select',
     '#title' => t('Default renewal schedule'),
     '#default_value' => variable_get('ec_file_default_schedule', 0),
@@ -267,6 +281,60 @@
     '#options' => $slist,
     '#weight' => -1
   );
+  }
+  $form['main']['file_expiry_setting'] = array(
+	  '#type' => 'select',
+	  '#title' => t('Make purchased downloads available for'),
+	  '#default_value' => variable_get('file_expiry_setting',''),
+	  '#options' => array(
+	    '1800' =>t('30 minutes') ,
+		  '3600' =>t('1 hour') ,
+		  '21600' =>t('6 hours') ,
+		  '43200' =>t('12 hours'),
+		  '86400' => t('24 hours'),
+		  '172800' => t('2 days'),
+		  '187200' => t('3 days'),),
+	  '#description' => t('<p>The length of time downloads will be available to download for, from the time payment and the order workflow has been set to completed. This option overrides the renewal schedule setting.<p> '),
+  	);
+  $form['amazons3'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('Amazon S3 Settings'),
+  );
+
+  $form['amazons3']['ec_amazons3_activate'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Activate Amazon S3 override'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('ec_amazons3_activate',0),
+    '#description' => t('Check this box if you want to override the default local file downloads folder onyour server and deliver the product downloads using your Amazon S3 Services bucket')
+    );
+
+  $form['amazons3']['ec_amazons3_access_code'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Access Key ID'),
+    '#default_value' => variable_get('ec_amazons3_access_code', ''),
+    '#cols' => 10, '#rows' => 1,
+    '#description' => t('Specify your Amazon S3 Access Key ID. You can find your <strong>Access Key ID</strong> by logging into your account and selecting ACCESS IDENTIFIERS from the YOUR ACCOUNT menu.'),
+
+  );
+  $form['amazons3']['ec_amazons3_secret_key'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Secret Access Key'),
+    '#default_value' => variable_get('ec_amazons3_secret_key', ''),
+    '#cols' => 15, '#rows' => 1,
+    '#description' => t('Specify your Amazon S3 Secret Access Key. You can find your <strong>Secret Access Key</strong> by logging into your account and selecting ACCESS IDENTIFIERS from the YOUR ACCOUNT menu.'),
+
+  );
+  $form['amazons3']['ec_amazons3_bucket'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Bucket'),
+    '#default_value' => variable_get('ec_amazons3_bucket', ''),
+    '#cols' => 10, '#rows' => 1,
+    '#description' => t('Specify the name of the Amazon s3 Bucket where you are storing your download files. Note: The file names of your file product downloads must be the same as stored in your Amazon S3 Bucket.'),
+  );
+
   return system_settings_form($form);
 }
 
@@ -325,72 +393,102 @@
 }
 
 /**
- * Print the files for the user to download.
- *
- * If the expired parameter is true, this will output a list of expired files instead.
+ * Display a list of files for the user to download.
  *
  * Note:
- * Expiration date is found via the sitewide file expiration date OR the
- * special case where a store admin has extended the expiration date for a given
- * transaction. The 'special case' always take precedence, so you can disable
- * downloads before the sitewide expiration date is reached.
- * 
- * TODO: this should really be a view.  this is a waste of a lot of code :)
- * TODO: until we add views this would be nice if it was a pager query.
+ * The expiration date is set in the ecommerce file admin settings page
+ * and is linked to the payment date for the transaction.
+ *
+ * Expired and active downloads are listed on the same page.
+ *
  */
 function file_my_overview($uid = FALSE, $expired = FALSE) {
 
+  // construct the page title
   $name = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $uid));
-
-  if ($expired) {
-    $output = t('<p><a href="!files-uri">Click here to view your files.</a></p>', array('!files-uri' => url('store/myfiles/'. $uid)));
-    $title = t('%username\'s expired files', array('%username' => $name));
-    $status = ECRECURRING_STATUS_EXPIRED;
-  }
-  else {
-    $output = t('<p><a href="!expired-files-uri">Click here to view your expired files.</a></p>', array('!expired-files-uri' => url("store/myfiles/$uid/expired")));
-    $title = t('%username\'s files', array('%username' => $name));
-    $status = ECRECURRING_STATUS_ACTIVE;
-  }
+  $title = t('%username\'s files', array('%username' => $name));
   drupal_set_title($title);
 
+  // define the table columns and default sort
   $header = array(
-    array('data' => t('filename'), 'field' => 't.txnid', 'sort' => 'desc'),
+    array('data' => t('title'), 'field' => 't.txnid', 'sort' => 'desc'),
     array('data' => t('size'), 'field' => 'epf.size'),
-    array('data' => ($expired) ? t('expired') : t('expires'), 'field' => 'ere.expiry'),
-    t('operations')
+    t('download link'),
+    t('expires'),
   );
 
-  // Checking for file to download involves at least 2 queries to the store
-  // transaction table. 1) Check if the user explicitly purchased a file download
-  // as 2) Check if the user purchased a multi-product which contains a file download.
 
-  // Check 1: Grab all explicit file downloads.
-  $result = db_query('SELECT etp.title, epf.size, epf.fpath, ere.expiry, t.workflow
-    FROM {ec_transaction} t
-      JOIN {ec_transaction_product} etp ON etp.txnid = t.txnid
-      JOIN {ec_product_file} epf ON epf.nid = etp.nid
-      LEFT OUTER JOIN {ec_recurring_expiration} ere ON ere.vid = etp.vid AND ere.txnid = etp.txnid
-    WHERE t.uid = %d AND ((ere.status = 0 AND ere.rid <= 0) OR ere.status IS NULL)'. tablesort_sql($header), $uid, $status);
+  // Load all file transactions that are set as workflow completed
+  $result = db_query('SELECT etp.title, epf.size, epf.fpath, t.payment_status, t.payment_date
+     FROM {ec_transaction} t
+       JOIN {ec_transaction_product} etp ON etp.txnid = t.txnid
+       JOIN {ec_product_file} epf ON epf.nid = etp.nid
+     WHERE t.uid = %d AND t.payment_status = 2 '. tablesort_sql($header), $uid);
+
+    // load the cutoff time which is set under the ecommerce file admin settings page.
+  $cutofftime = variable_get('file_expiry_setting','');
+
+
+  // remove download link and replace with the text expired if the file download has expired
   while ($data = db_fetch_object($result)) {
-    if ($data->workflow == EC_WORKFLOW_COMPLETED) {
+    if (($data->payment_status == 2) && ((time() - $data->payment_date) <= $cutofftime)) { // if the workflow is set to completed and the expiry time is less than the current time
       $dload_link = t('<a href="!file-download-uri">download</a>', array('!file-download-uri' => ec_file_create_url($data->fpath)));
     }
-    else {
-      $dload_link = t('Transaction %status', array('%status' => transaction_get_workflow($data->workflow)));
+    if (($data->payment_status == 2) && ((time() - $data->payment_date) > $cutofftime)) {// if the workflow is set to completed and the expiry time is greater than the current time
+     $dload_link = t('Expired');
     }
 
-    if ($expired) {
-      $rows[] = array(theme('placeholder', $data->title), format_size($data->size), t('%interval ago', array('%interval' => format_interval($data->expiry - time(), 3))), '');
-    }
-    else {
-      $rows[] = array(theme('placeholder', $data->title), format_size($data->size), format_interval($data->expiry - time(), 3), $dload_link);
+    // define some variables
+    //$paid_date = date('M-D-Y (h:m)',$data->payment_date);
+    $expiry_date =  ($data->payment_date + $cutofftime);
+    $due_date = format_interval($expiry_date - time());
+
+    // change the expires string in the table to be time ago if the file has expired
+    if (time() - $data->payment_date >= $cutofftime) {
+        $due_date =  t('%interval ago', array('%interval' => format_interval(time() - ($data->payment_date + $cutofftime))));
     }
+    // construct the table row for this file
+    $rows[] = array(theme('placeholder', $data->title), format_size($data->size),  $dload_link, $due_date);
+
   }
+  // Check 2: check all parcel products that include a file product
 
-  // Check 2: Check for multi products that contain file downloads.
-  // Multi products(parcels) don't work 100% with subscriptions so we can't use them currently.
+ if (module_exists('parcel')) {
+ $data = '';
+ $result2 = db_query('SELECT etp.nid, epf.size, epp.mnid, epf.fpath, t.payment_status, t.payment_date, epn.title
+    FROM {ec_transaction} t
+      JOIN {ec_transaction_product} etp ON etp.txnid = t.txnid
+      JOIN {ec_product_parcel} epp ON epp.nid = etp.nid
+      JOIN {ec_product_file} epf ON epf.nid = epp.mnid
+      JOIN {node} epn ON epn.nid = epf.nid
+    WHERE t.uid = %d AND t.payment_status = 2 '. tablesort_sql($header), $uid);
+
+  while ($data = db_fetch_object($result2)) {
+    if (($data->payment_status == 2) && ((time() - $data->payment_date) <= $cutofftime)) { // if the workflow is set to completed and the expiry time is less than the current time
+      $dload_link = t('<a href="!file-download-uri">download</a>', array('!file-download-uri' => ec_file_create_url($data->fpath)));
+    }
+    if (($data->payment_status == 2) && ((time() - $data->payment_date) > $cutofftime)) {// if the workflow is set to completed and the expiry time is greater than the current time
+     $dload_link = t('Expired');
+    }
+
+    // define some variables
+    //$paid_date = date('M-D-Y (h:m)',$data->payment_date);
+    $expiry_date =  ($data->payment_date + $cutofftime);
+    $due_date = format_interval($expiry_date - time());
+
+    // change the expires string in the table to be time ago if the file has expired
+    if (time() - $data->payment_date >= $cutofftime) {
+        $due_date =  t('%interval ago', array('%interval' => format_interval(time() - ($data->payment_date + $cutofftime))));
+    }
 
+    // construct the table row for this file
+    $rows[] = array(theme('placeholder', $data->title), format_size($data->size), $dload_link,  $due_date);
+
+   }
+  } // end of parcel module check
+
+
+  // build the myfiles table
   $output .= ($rows) ? theme('table', $header, $rows) : t('You have no files to download.');
 
   return $output;
@@ -474,18 +572,50 @@
 }
 
 function ec_file_may_download($file, $uid) {
-  // TODO: cache results to avoid repeated queries
 
-  $data = db_fetch_object(db_query("SELECT st.txnid, stp.vid FROM {ec_transaction} AS st
+  $data = db_fetch_object(db_query("SELECT st.txnid, stp.vid, st.payment_date, st.payment_status
+  FROM {ec_transaction} AS st
       JOIN {ec_transaction_product} AS stp ON stp.txnid = st.txnid
       JOIN {ec_product_file} AS pf ON pf.nid = stp.nid
     WHERE st.uid = %d
-      AND st.workflow = %d
-      AND pf.fpath = '%s'", $uid, EC_WORKFLOW_COMPLETED, $file));
+      AND st.payment_status = 2
+      AND pf.fpath = '%s'
+    Order by st.payment_date DESC", $uid, $file));
+
+
 
+
+// ec_recurring override
   if (!empty($data)) {
-    return !ec_recurring_product_get_expiry($data->txnid, $data->vid);
-  }
+      // return false if the cutofftime has expired.
+      $cutofftime = variable_get('file_expiry_setting','');
+      if (time() - $data->payment_date > $cutofftime) {
+        return false;
+      }
+      else {
+        return true;
+      }
+     }
+ $parceldata= db_fetch_object(db_query("SELECT st.txnid, stp.vid, st.payment_date,  st.payment_status
+  FROM {ec_transaction} AS st
+      JOIN {ec_transaction_product} AS stp ON stp.txnid = st.txnid
+      JOIN {ec_product_parcel} AS epp ON epp.nid = stp.nid
+      JOIN {ec_product_file} AS pf ON pf.nid = epp.mnid
+    WHERE st.uid = %d
+      AND st.payment_status = 2
+      AND pf.fpath = '%s'", $uid, $file));
+
+// ec_recurring override
+  if (!empty($parceldata)) {
+      // return false if the cutofftime has expired.
+      $cutofftime = variable_get('file_expiry_setting','');
+      if (time() - $parceldata->payment_date > $cutofftime) {
+        return false;
+      }
+      else {
+        return true;
+      }
+     }
   else {
     return false;
   }
@@ -509,7 +639,6 @@
     if (file_iemac_hack() && strlen($filename) > 30) {
       $filename = substr($filename, strlen($filename) - 30);
     }
-
     $file = ec_file_create_path($file);
     $header[] = 'Content-type: application/x-download';
     $header[] = 'Content-Disposition: attachment; filename="'. $filename .'";';
@@ -531,20 +660,35 @@
  */
 function ec_file_transfer($source, $headers) {
   ob_end_clean();
-
-  foreach ($headers as $header) {
-    header($header);
+    foreach ($headers as $header) {
+     header($header);
   }
+  if (variable_get('ec_amazons3_activate',0)) {
+    // amazon s3 integration
+    require_once('hmac.php');
+    $expiry = time() + 3600; //link will work for 1 hour after this page is generated.
+    $bucket = variable_get('ec_amazons3_bucket', '');
+    //  $filename = $downloads['orders_products_filename'];
+    $access_key = variable_get('ec_amazons3_access_code', '');
+    $very_secret_key = variable_get('ec_amazons3_secret_key', '');
+    $stringtosign = "GET\n\n\n$expiry\n/$bucket/$source";
+    $hasher = new Crypt_HMAC($very_secret_key, "sha1");
+    $sig = urlencode(s3hex($hasher->hash($stringtosign)));
+    $amazonurl = "http://$bucket.s3.amazonaws.com/$source?AWSAccessKeyId=$access_key&Expires=$expiry&Signature=$sig";
+    header("Location: $amazonurl");
+	  exit();
+	  }
+	else {
+   $source = ec_file_create_path($source);
+    // Transfer file in 1024 byte chunks to save memory usage.
+    $fd = fopen($source, 'rb');
+    while (!feof($fd)) {
+      print fread($fd, 1024);
+      }
+    fclose($fd);
+    exit();
+    }
 
-  $source = ec_file_create_path($source);
-
-  // Transfer file in 1024 byte chunks to save memory usage.
-  $fd = fopen($source, 'rb');
-  while (!feof($fd)) {
-    print fread($fd, 1024);
-  }
-  fclose($fd);
-  exit();
 }
 
 /**
@@ -681,3 +825,37 @@
     }
   }
 }
+/*
+ * Calculate HMAC-SHA1 according to RFC2104
+ * See http://www.faqs.org/rfcs/rfc2104.html
+ */
+function hmacsha1($key,$data) {
+    $blocksize=64;
+    $hashfunc='sha1';
+    if (strlen($key)>$blocksize)
+        $key=pack('H*', $hashfunc($key));
+    $key=str_pad($key,$blocksize,chr(0x00));
+    $ipad=str_repeat(chr(0x36),$blocksize);
+    $opad=str_repeat(chr(0x5c),$blocksize);
+    $hmac = pack(
+                'H*',$hashfunc(
+                    ($key^$opad).pack(
+                        'H*',$hashfunc(
+                            ($key^$ipad).$data
+                        )
+                    )
+                )
+            );
+    return bin2hex($hmac);
+}
+
+
+function s3hex($str)
+{
+    $raw = '';
+    for ($i=0; $i < strlen($str); $i+=2)
+    {
+        $raw .= chr(hexdec(substr($str, $i, 2)));
+    }
+    return base64_encode($raw);
+}
\ No newline at end of file

