Index: demo.admin.inc
===================================================================
--- demo.admin.inc	(revision 246)
+++ demo.admin.inc	(working copy)
@@ -11,7 +11,7 @@
  */
 define('DEMO_DUMP_VERSION', '1.1');
 
-function _demo_admin_settings() {
+function demo_admin_settings() {
   global $base_url;
 
   $form['status'] = array(
@@ -77,7 +77,7 @@ function demo_admin_settings_submit($for
   drupal_set_message(t('The configuration options have been saved.'));
 }
 
-function _demo_manage() {
+function demo_manage() {
   $form['dump'] = array(
     '#type' => 'fieldset',
     '#title' => t('Available snapshots'),
@@ -105,7 +105,7 @@ function demo_manage_submit($form_id, $v
   }
 }
 
-function _demo_delete_confirm($filename = '') {
+function demo_delete_confirm($filename = '') {
   $fileconfig = demo_get_fileconfig($filename);
   if (!file_exists($fileconfig['infofile'])) {
     return drupal_access_denied();
@@ -126,7 +126,7 @@ function demo_delete_confirm_submit($for
   return 'admin/build/demo/manage';
 }
 
-function _demo_dump() {
+function demo_dump() {
   $form = array();
   $form['dump']['filename'] = array(
     '#title' => t('File name'),
@@ -196,7 +196,7 @@ function demo_dump_submit($form_id, $val
   drupal_goto('admin/build/demo/manage');
 }
 
-function _demo_reset_confirm() {
+function demo_reset_confirm() {
   $form['dump'] = array(
     '#type' => 'fieldset',
     '#title' => t('Available snapshots'),
@@ -372,8 +372,13 @@ function demo_get_dumps() {
     }
     $option['#description'] = '';
     if (!empty($info['description'])) {
-      $option['#description'] .= $info['description'] . '<br /><br />';
+      $option['#description'] .= '<p>' . $info['description'] . '</p>';
     }
+    $targs = array(
+      '@info-file-url' => url('demo/download/' . $file->name . '/info'),
+      '@sql-file-url' => url('demo/download/' . $file->name . '/sql'),
+    );
+    $option['#description'] .= '<p>' . t('Download: <a href="@info-file-url">.info file</a>, <a href="@sql-file-url">.sql file</a>', $targs) . '</p>';
     if (count($info['modules']) > 1) {
       // Remove required core modules and obvious modules from module list.
       $info['modules'] = array_diff($info['modules'], array('block', 'filter', 'node', 'system', 'user', 'watchdog', 'demo'));
@@ -519,7 +524,7 @@ function demo_enum_tables() {
  * Retrieve a pipe delimited string of autocomplete suggestions for existing
  * snapshot names.
  */
-function _demo_autocomplete($string = '') {
+function demo_autocomplete($string = '') {
   $matches = array();
   if ($string && $fileconfig = demo_get_fileconfig()) {
     $string = preg_quote($string);
@@ -533,6 +538,31 @@ function _demo_autocomplete($string = ''
 }
 
 /**
+ * Transfer (download) a snapshot file.
+ *
+ * @param $filename
+ *   The snapshot filename to transfer.
+ * @param $type
+ *   The file type, i.e. extension to transfer.
+ *
+ * @todo Allow to download an bundled archive of snapshot files.
+ */
+function demo_download($filename, $type) {
+  $fileconfig = demo_get_fileconfig($filename);
+  if (!isset($fileconfig[$type . 'file']) || !file_exists($fileconfig[$type . 'file'])) {
+    return MENU_NOT_FOUND;
+  }
+  // Force the client to re-download and trigger a file save download.
+  $headers = array(
+    'Cache-Control: private',
+    'Content-Type: application/octet-stream',
+    'Content-Length: ' . filesize($fileconfig[$type . 'file']),
+    'Content-Disposition: attachment, filename=' . $fileconfig[$type],
+  );
+  file_transfer($fileconfig[$type . 'file'], $headers);
+}
+
+/**
  * Sets a specific snapshot as default for cron runs or the site reset block.
  *
  * @param $filename
Index: demo.module
===================================================================
--- demo.module	(revision 246)
+++ demo.module	(working copy)
@@ -71,11 +71,19 @@ function demo_menu($may_cache) {
     );
     $items[] = array(
       'path' => 'demo/autocomplete',
-      'title' => t('Demo Site autocomplete'),
       'callback' => 'demo_autocomplete',
       'access' => $admin_access,
       'type' => MENU_CALLBACK,
     );
+    $items[] = array(
+      'path' => 'demo/download',
+      'callback' => 'demo_download',
+      'access' => $admin_access,
+      'type' => MENU_CALLBACK,
+    );
+  }
+  else if (strpos($_GET['q'], 'admin/build/demo') === 0 || strpos($_GET['q'], 'demo') === 0) {
+    require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
   }
   return $items;
 }
@@ -137,33 +145,3 @@ function demo_cron() {
   }
 }
 
-function demo_admin_settings() {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_admin_settings();
-}
-
-function demo_manage() {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_manage();
-}
-
-function demo_dump() {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_dump();
-}
-
-function demo_reset_confirm() {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_reset_confirm();
-}
-
-function demo_delete_confirm($filename) {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_delete_confirm($filename);
-}
-
-function demo_autocomplete($string = '') {
-  require_once drupal_get_path('module', 'demo') . '/demo.admin.inc';
-  return _demo_autocomplete($string);
-}
-
