--- /dev/null
+++ mailing_list.admin.inc
@@ -0,0 +1,407 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Mailing list admin UI.
+ */
+
+/**
+ * Menu callback; displays all mailing lists in a table.
+ */
+function mailing_list_lists() {
+  $header = array(
+    array('data' => t('Name'), 'field' => 'name', 'sort' => 'asc'),
+    array('data' => t('Operations'), 'colspan' => '5')
+  );
+
+  $query  = "SELECT * FROM {mailing_list}";
+  $result = db_query($query);
+  $rows = array();
+  $destination = drupal_get_destination();
+  while ($list = db_fetch_object($result)) {
+    $row = array(l(check_plain($list->name), "admin/build/mailing-list/$list->mlid"), l(t('list e-mails'), "admin/build/mailing-list/$list->mlid"), l(t('import e-mails'), "admin/build/mailing-list/$list->mlid/import", array('query' => $destination)), l(t('export list'), "admin/build/mailing-list/$list->mlid/export", array('query' => $destination)), l(t('rename list'), "admin/build/mailing-list/$list->mlid/edit", array('query' => $destination)), l(t('delete list'), "admin/build/mailing-list/$list->mlid/delete", array('query' => $destination)));
+    $rows[] = $row;
+  }
+
+  if (empty($rows)) {
+    $empty_message = t('No mailing lists found.');
+    $rows[] = array(array('data' => $empty_message, 'colspan' => 6));
+  }
+
+  $output = theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 50, 0);
+
+  return $output;
+}
+
+/**
+ * Menu callback; displays all e-mails for the specified mailing list in a
+ * table.
+ */
+function mailing_list_emails($list = NULL) {
+  if (empty($list)) {
+    return;
+  }
+  else {
+    drupal_set_title(check_plain($list->name));
+  }
+
+  $sql = 'SELECT * FROM {mailing_list_emails} WHERE mlid = %d';
+
+  $header = array(
+    array('data' => t('E-mail'), 'field' => 'mail', 'sort' => 'asc'),
+    array('data' => t('Name'), 'field' => 'name'),
+    array('data' => t('Operations'), 'colspan' => '2')
+  );
+  $sql .= tablesort_sql($header);
+  $result = pager_query($sql, 50, 0 , NULL, array($list->mlid));
+
+  $rows = array();
+  $destination = drupal_get_destination();
+  while ($data = db_fetch_object($result)) {
+    $row = array(check_plain($data->mail), (!empty($data->name) ? check_plain($data->name) : theme('placeholder', t('none'))), l(t('edit'), "admin/build/mailing-list/$list->mlid/$data->eid", array('query' => $destination)), l(t('delete'), "admin/build/mailing-list/$list->mlid/$data->eid/delete", array('query' => $destination)));
+    $rows[] = $row;
+  }
+
+  if (empty($rows)) {
+    $empty_message = t('No e-mails found.');
+    $rows[] = array(array('data' => $empty_message, 'colspan' => 4));
+  }
+
+  $output = theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 50, 0);
+
+  return $output;
+}
+
+/**
+ * Form for adding / renaming a mailing list.
+ */
+function mailing_list_form(&$form_state, $list = null) {
+  if (empty($list)) {
+    drupal_set_title(t('Add mailing list'));
+  }
+  else {
+    drupal_set_title(t('Edit mailing list'));
+  }
+
+  $form = array();
+  if (isset($form_state['values']['mlid']) || isset($list)) {
+    $form['mlid'] = array(
+      '#type' => 'hidden',
+      '#value' => isset($form_state['values']['mlid']) ? $form_state['values']['mlid'] : isset($list) ? $list->mlid: null,
+    );
+  }
+
+  $form['name'] = array(
+    '#title' => t('List name'),
+    '#type' => 'textfield',
+    '#required' => TRUE,
+    '#default_value'=> isset($form_state['values']['name']) ? $form_state['values']['name']: isset($list)?$list->name : '',
+  );
+  $form['submit'] = array(
+    '#value' => t('Save'),
+    '#type' => 'submit',
+    '#submit' => array('mailing_list_form_submit'),
+  );
+  $form['#redirect'] = 'admin/build/mailing-list';
+
+  return $form;
+}
+
+/**
+ * Submit handler for the add / rename mailing list form.
+ */
+function mailing_list_form_submit($form, &$form_state) {
+  if (isset($form_state['values']['mlid'])) {
+    $query = "UPDATE {mailing_list} SET name = '%s' WHERE mlid = %d";
+    $result = db_query($query, $form_state['values']['name'], $form_state['values']['mlid']);
+  }
+  else {
+    $query = "INSERT INTO {mailing_list} (name) VALUES ('%s')";
+    $result = db_query($query, $form_state['values']['name']);
+  }
+
+  if ($result) {
+    if (isset($form_state['values']['mlid']) ) {
+      drupal_set_message(t('Renamed mailing list %name', array('%name' => $form_state['values']['name'])));
+      watchdog('mailing_list', 'Mailing list: renamed %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mailing-list/'. $form_state['values']['mlid']));
+    }
+    else {
+      drupal_set_message(t('Created mailing list %name', array('%name' => $form_state['values']['name'])));
+      watchdog('mailing_list', 'Mailing list: created %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mailing-list/'. $form_state['values']['mlid']));
+    }
+  }
+  else {
+    if (isset($form_state['values']['mlid'])) {
+      drupal_set_message(t('Failed to update mailing list %name', array('%name' => $form_state['values']['name'])), 'error');
+    }
+    else {
+      drupal_set_message(t('Failed to create mailing list %name', array('%name' => $form_state['values']['name'])), 'error');
+    }
+  }
+}
+
+/**
+ * Form to add / edit an e-mail in a mailing list.
+ */
+function mailing_list_email_form(&$form_state, $list = null, $email = null) {
+  if (empty($list)) {
+    return;
+  }
+
+  if (empty($email)) {
+    drupal_set_title(t('Add e-mail'));
+  }
+  else {
+    drupal_set_title(t('Edit e-mail'));
+  }
+
+  $form = array();
+  if (isset($form_state['values']['mlid']) || isset($list)) {
+    $form['mlid']   = array(
+      '#type' => 'hidden',
+      '#value' => isset($form_state['values']['mlid']) ? $form_state['values']['mlid'] : isset($list) ? $list->mlid: null,
+    );
+  }
+  if (isset($form_state['values']['eid']) || isset($email)) {
+    $form['eid'] = array(
+      '#type' => 'hidden',
+      '#value' => isset($form_state['values']['eid']) ? $form_state['values']['eid'] : isset($email) ? $email->eid: null,
+    );
+  }
+  $form['mail'] = array(
+    '#title' => t('E-mail'),
+    '#type' => 'textfield',
+    '#required' => TRUE,
+    '#default_value'=> isset($form_state['values']['mail']) ? $form_state['values']['mail']: isset($email) ? $email->mail : '',
+  );
+  $form['name'] = array(
+    '#title' => t('Name'),
+    '#type' => 'textfield',
+    '#default_value'=> isset($form_state['values']['name']) ? $form_state['values']['name']: isset($email) ? $email->name : '',
+  );
+  $form['submit'] = array(
+    '#value' => t('Save'),
+    '#type' => 'submit',
+    '#submit' => array('mailing_list_email_form_submit'),
+  );
+  $form['#redirect'] = 'admin/build/mailing-list/'. $list->mlid;
+  return $form;
+}
+
+/**
+ * Submit handler for the add / edit e-mail form.
+ */
+function mailing_list_email_form_submit($form, &$form_state) {
+  if (isset($form_state['values']['eid'])) {
+    $query = "UPDATE {mailing_list_emails} SET name = '%s', mail = '%s' WHERE eid = %d";
+    $result = db_query($query, $form_state['values']['name'], $form_state['values']['mail'], $form_state['values']['eid']);
+  }
+  else {
+    $query = "INSERT INTO {mailing_list_emails} (mlid, name, mail) VALUES (%d, '%s', '%s')";
+    $result = db_query($query, $form_state['values']['mlid'], $form_state['values']['name'], $form_state['values']['mail']);
+  }
+
+  $name = mailing_list_email_get_name($form_state['values']);
+  if ($result) {
+    if (isset($form_state['values']['eid']) ) {
+      drupal_set_message(t('Updated e-mail for %name', array('%name' => $name)));
+      watchdog('mailing_list', 'Mailing list: updated e-mail for %name.', array('%name' => $name), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mailing-list/'. $form_state['values']['mlid'] .'/'. $form_state['values']['eid']));
+    }
+    else {
+      drupal_set_message(t('Added e-mail for %name', array('%name' => $name)));
+      watchdog('mailing_list', 'Mailing list: added e-mail for %name.', array('%name' => $name));
+    }
+  }
+  else {
+    if (isset($form_state['values']['eid'])) {
+      drupal_set_message(t('Failed to update e-mail for %name', array('%name' => $name)), 'error');
+    }
+    else {
+      drupal_set_message(t('Failed to add e-mail for %name', array('%name' => $name)), 'error');
+    }
+  }
+}
+
+/**
+ * Mailing list deletion form.
+ */
+function mailing_list_delete_confirm($form_state, $list) {
+  if (user_access('administer mailing lists')) {
+    $form['mlid'] = array('#type' => 'value', '#value' => $list->mlid);
+    $form['name'] = array('#type' => 'value', '#value' => $list->name);
+    $output = confirm_form($form,
+      t('Are you sure you want to delete mailing list %name? All e-mails in this list will be deleted too.', array('%name' => $list->name)),
+      isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/mailing-list');
+  }
+  return $output;
+}
+
+/**
+ * Submit handler for the mailing list deletion form.
+ */
+function mailing_list_delete_confirm_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    mailing_list_delete($form_state['values']['mlid']);
+    drupal_set_message(t('Deleted mailing list %name.', array('%name' => $form_state['values']['name'])));
+    watchdog('mailing list', 'Mailing list: deleted list %name.', array('%name' => $form_state['values']['name']));
+    $form_state['redirect'] = 'admin/build/mailing-list';
+    return;
+  }
+}
+
+/**
+ * E-mail deletion form.
+ */
+function mailing_list_email_delete_confirm($form_state, $list, $email) {
+  if (user_access('administer mailing lists')) {
+    $name = mailing_list_email_get_name($email);
+    $form['mlid'] = array('#type' => 'value', '#value' => $list->mlid);
+    $form['eid'] = array('#type' => 'value', '#value' => $email->eid);
+    $form['name'] = array('#type' => 'value', '#value' => $name);
+    $output = confirm_form($form,
+      t('Are you sure you want to delete the e-mail for %name?', array('%name' => $name)),
+      isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/mailing-list/'. $list->mlid);
+  }
+  return $output;
+}
+
+/**
+ * Submit handler for the e-mail deletion form.
+ */
+function mailing_list_email_delete_confirm_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    mailing_list_email_delete($form_state['values']['eid']);
+    drupal_set_message(t('E-mail deleted for %name', array('%name' => $form_state['values']['name'])));
+    $form_state['redirect'] = 'admin/build/mailing-list/'. $form_state['values']['mlid'];
+    watchdog('mailing list', 'Mailing list: deleted e-mail %name.', array('%name' => $form_state['values']['name']));
+    return;
+  }
+}
+
+/**
+ * Deletes a mailing list and all its e-mails.
+ *
+ * @param $mlid
+ *   The ID of the mailing list.
+ */
+function mailing_list_delete($mlid) {
+  db_query('DELETE FROM {mailing_list_emails} WHERE mlid = %d', $mlid);
+  db_query('DELETE FROM {mailing_list} WHERE mlid = %d', $mlid);
+}
+
+/**
+ * Deletes an e-mail.
+ *
+ * @param $eid
+ *   The ID of the e-mail.
+ */
+function mailing_list_email_delete($eid) {
+  db_query('DELETE FROM {mailing_list_emails} WHERE eid = %d', $eid);
+}
+
+/**
+ * Form for importing a mailing list from a CSV file.
+ */
+function mailing_list_import_form($form_state, $list) {
+  if (empty($list)) {
+    return;
+  }
+
+  drupal_set_title(t('Import e-mails'));
+
+  $form = array();
+  $form['#attributes'] = array('enctype' => "multipart/form-data");
+  if ( isset($form_state['values']['mlid']) || isset($list) ) {
+    $form['mlid']   = array(
+      '#type'       => 'hidden',
+      '#value'      => isset($form_state['values']['mlid']) ? $form_state['values']['mlid'] : isset($list) ? $list->mlid: null,
+    );
+  }
+  if ( isset($form_state['values']['name']) || isset($list) ) {
+    $form['name']   = array(
+      '#type'       => 'hidden',
+      '#value'      => isset($form_state['values']['name']) ? $form_state['values']['name'] : isset($list) ? $list->name: null,
+    );
+  }
+  $form['file_upload'] = array(
+    '#title'      => t('CSV file'),
+    '#type'       => 'file',
+  );
+  $form['submit'] = array(
+    '#value'      => t('Import'),
+    '#type'       => 'submit',
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the mailing list import form.
+ */
+function mailing_list_import_form_submit($form, &$form_state) {
+  $num_imported = 0;
+
+  if ($file = file_save_upload('file_upload', array('file_validate_extensions' => array('csv')))) {
+    ini_set('auto_detect_line_endings',TRUE);
+    $handle = @fopen($file->filepath, 'r');
+
+    while (($data = fgetcsv($handle)) !== FALSE) {
+      $num_fields = count($data);
+      $is_existing = db_fetch_object(db_query("SELECT * from {mailing_list_emails} WHERE mlid = %d AND mail = '%s'", $form_state['values']['mlid'], $data[0]));
+      if (!$is_existing && $num_fields == 2) {
+        db_query("INSERT INTO {mailing_list_emails} (mlid, mail, name) VALUES (%d, '%s', '%s')", $form_state['values']['mlid'], $data[0], $data[1]);
+        $num_imported++;
+      }
+    }
+
+    fclose($handle);
+
+    if ($num_imported) {
+      drupal_set_message(t('Import complete: %num-imported added to mailing list %name.', array('%num-imported' => format_plural($num_imported, '1 e-mail', '@count e-mails'), '%name' => $form_state['values']['name'])));
+    }
+  }
+
+  if (!$num_imported) {
+    drupal_set_message(t('No e-mails added to mailing list: invalid or empty file.'), 'error');
+  }
+
+  $form_state['redirect'] = 'admin/build/mailing-list/'. $form_state['values']['mlid'];
+
+  return;
+}
+
+/**
+ * Menu callback; exports a mailing list directly to the user as a CSV file.
+ */
+function mailing_list_export($list) {
+	$path = file_directory_path();
+
+	// create file to hold email list
+	$filename = drupal_strtolower(str_replace(' ', '_', $list->name)). '.csv';
+	$full_path = $path.'/'.$filename;
+
+	$query = "SELECT * FROM {mailing_list_emails} WHERE mlid = '%d'";
+	$result = db_query($query, $list->mlid);
+
+	// create string with all the emails
+	$emails = array();
+	while ($row = db_fetch_object($result)) {
+		$emails[] = '"'. trim($row->mail) .'","'. trim($row->name) .'"';
+	}
+
+	$emails = implode("\n", $emails) ."\n";
+
+	// write resultant string to file
+	file_save_data($emails, $full_path, FILE_EXISTS_REPLACE);
+
+	// set headers for file transfer
+	$headers = array(
+		'Content-Type: application/octet-stream',
+		'Content-Disposition: attachment; filename="' . basename($full_path) . '";',
+		'Content-Length: ' . sprintf('%u', filesize($full_path)),
+	);
+
+	file_transfer($full_path, $headers);
+}
--- mailing_list.install
+++ mailing_list.install
@@ -1,57 +1,165 @@
 <?php
+// $Id$
 
+/**
+ * @file
+ * Install and update functions for mailing_list.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
 function mailing_list_install() {
   drupal_install_schema('mailing_list');
 }
 
+/**
+ * Implementation of hook_uninstall().
+ */
 function mailing_list_uninstall() {
   drupal_uninstall_schema('mailing_list');
   db_query("DELETE FROM {blocks} WHERE module = 'mailing_list'");
 }
 
-
+/**
+ * Implementation of hook_schema().
+ */
 function mailing_list_schema() {
   $schema = array();
   $schema['mailing_list'] = array(
-    'description' => t('Mailing list id'),
+    'description' => t('A mailing list consisting of names and e-mails.'),
     'fields' => array(
-      'id'        => array(
-        'type'    => 'serial',
+      'mlid' => array(
+        'description' => 'The primary identifier for a mailing list.',
+        'type' => 'serial',
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
-      'list'  =>  array(
-        'description' => t('The title of this mailing list'),
+      'name' => array(
+        'description' => t('The title of this mailing list.'),
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
       ),
     ),
-    'primary key' => array('id'),  
+    'primary key' => array('mlid'),
+    'indexes' => array(
+      'name' => array('name'),
+    ),
   );
   $schema['mailing_list_emails'] = array(
-    'description' => t('Emails subscribed to specific fields'),
+    'description' => t('An e-mail in a mailing list.'),
     'fields' => array(
-      'id'        => array(
-        'type'    => 'serial',
+      'eid' => array(
+        'description' => 'The primary identifier for a mailing list e-mail.',
+        'type' => 'serial',
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
-      'mailing_list_id' => array(
-      	'description' => t('Which mailing list the address is subscribed to.'),
+      'mlid' => array(
+      	'description' => t('The {mailing_list} this e-mail belongs to.'),
       	'type' => 'int',
+        'unsigned' => TRUE,
       	'not null' => TRUE,
+        'default' => 0,
       ),
-      'email'  =>  array(
-        'description' => t('The title of this mailing list'),
+      'mail' => array(
+        'description' => t('The e-mail of this subscriber.'),
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
       ),
+      'name' => array(
+        'description' => t('The name of this subscriber.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('eid'),
+    'indexes' => array(
+      'mlid' => array('mlid'),
+      'name' => array('name'),
+    ),
+    'unique keys' => array(
+      'mail' => array('mail'),
     ),
-    'primary key' => array('id'),  
   );
-  
-  
+
+
   return $schema;
 }
+
+/**
+ * Update mailing lists to allow subscriber names (not just e-mails), and clean
+ * up field names.
+ */
+function mailing_list_update_6000() {
+  $ret = array();
+
+  db_change_field($ret, 'mailing_list', 'id', 'mlid',
+    array(
+      'type' => 'serial',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+    )
+  );
+
+  db_change_field($ret, 'mailing_list', 'list', 'name',
+    array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => TRUE,
+    ),
+    array(
+      'indexes' => array(
+        'name' => array('name'),
+      ),
+    )
+  );
+
+  db_change_field($ret, 'mailing_list_emails', 'id', 'eid',
+    array(
+      'type' => 'serial',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+    )
+  );
+
+  db_change_field($ret, 'mailing_list_emails', 'mailing_list_id', 'mlid',
+    array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+    ),
+    array(
+      'indexes' => array(
+        'mlid' => array('mlid'),
+      ),
+    )
+  );
+
+  db_change_field($ret, 'mailing_list_emails', 'email', 'mail',
+    array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => TRUE,
+    ),
+    array(
+      'unique keys' => array(
+        'mail' => array('mail'),
+      ),
+    )
+  );
+
+  db_add_field($ret, 'mailing_list_emails', 'name', array('type' => 'varchar', 'not null' => TRUE, 'length' => 255), array('indexes' => array('name' => array('name'))));
+
+  $ret[] = update_sql("DELETE FROM {permission} WHERE perm = 'export mailing list'");
+  $result = db_query("SELECT rid, perm FROM {permission} WHERE perm = 'administer mailing list' ORDER BY rid");
+  while ($role = db_fetch_object($result)) {
+    $ret[] = update_sql("UPDATE {permission} SET perm = 'administer mailing lists' WHERE rid = $role->rid");
+  }
+
+  return $ret;
+}
diff --git a/mailing_list.module b/mailing_list.module
index 81fcee0..a145f1d 100644
--- mailing_list.module
+++ mailing_list.module
@@ -1,219 +1,288 @@
 <?php
 // $Id: mailing_list.module,v 1.3 2009/07/31 14:10:40 litwol Exp $
+
+/**
+ * @file
+ * Minimalistic mailing list module.
+ */
+
+/**
+ * Implementation of hook_help().
+ */
+function mailing_list_help($path, $arg) {
+  if ($path == 'admin/build/mailing-list/%/import') {
+    return t('The import facility allows you to upload a CSV file containing e-mail addresses, and optional names, to add to your mailing list. The CSV file should have the e-mails as its first column, and the names (where available) as its second column. It must not have any header row.');
+  }
+}
+
+/**
+ * Implementation of hook_perm().
+ */
 function mailing_list_perm() {
-  return array('administer mailing list', 'export mailing list');
+  return array('administer mailing lists');
 }
 
+/**
+ * Implementation of hook_menu().
+ */
 function mailing_list_menu() {
   $items = array();
-  $items['admin/settings/mailing-list'] = array(
-    'title'             => t('Mailing List'),
-    'page callback'     => 'mailing_list_admin',
-    'access arguments'  => array('administer mailing list'),
+
+  $items['admin/build/mailing-list'] = array(
+    'title' => t('Mailing lists'),
+    'description' => t('Manage your mailing lists.'),
+    'page callback' => 'mailing_list_lists',
+    'access arguments' => array('administer mailing lists'),
+    'file' => 'mailing_list.admin.inc',
   );
-  $items['admin/settings/mailing-list/%mailing_list/edit'] = array(
-    'title'             => t('Edit Mailing List'),
-    'page callback'     => 'drupal_get_form',
-    'page arguments'=> array('mailing_list_form', 3),
-    'access arguments'  => array('administer mailing list'),
+  $items['admin/build/mailing-list/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
   );
-
-  $items['mailing-list/%mailing_list/export'] = array(
-  	'title' => t('Export Mailing List'),
+  $items['admin/build/mailing-list/add'] = array(
+    'title' => t('Add'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_form'),
+    'access arguments' => array('administer mailing lists'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list'] = array(
+    'title' => 'List e-mails',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'mailing_list_emails',
+    'page arguments' => array(3),
+    'access arguments' => array('administer mailing lists'),
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list/list'] = array(
+    'title' => 'List e-mails',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/build/mailing-list/%mailing_list/add'] = array(
+    'title' => t('Add e-mail'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_email_form', 3),
+    'access arguments' => array('administer mailing lists'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => -5,
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list/import'] = array(
+  	'title' => t('Import e-mails'),
+  	'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_import_form', 3),
+		'access arguments' => array('administer mailing lists'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => -2,
+    'file' => 'mailing_list.admin.inc',
+	);
+  $items['admin/build/mailing-list/%mailing_list/export'] = array(
+  	'title' => t('Export list'),
   	'page callback' => 'mailing_list_export',
-		'page arguments' => array(1),
-		'access arguments' => array('export mailing list'),
+		'page arguments' => array(3),
+		'access arguments' => array('administer mailing lists'),
+		'type' => MENU_LOCAL_TASK,
+    'weight' => 0,
+    'file' => 'mailing_list.admin.inc',
 	);
+	$items['admin/build/mailing-list/%mailing_list/edit'] = array(
+    'title' => t('Rename list'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_form', 3),
+    'access arguments' => array('administer mailing lists'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 5,
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list/delete'] = array(
+    'title' => 'Delete list',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_delete_confirm', 3),
+    'access arguments' => array('administer mailing lists'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10,
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list/%mailing_list_email'] = array(
+    'title' => 'Edit e-mail',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_email_form', 3, 4),
+    'access arguments' => array('administer mailing lists'),
+    'file' => 'mailing_list.admin.inc',
+  );
+  $items['admin/build/mailing-list/%mailing_list/%mailing_list_email/delete'] = array(
+    'title' => 'Delete e-mail',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mailing_list_email_delete_confirm', 3, 4),
+    'access arguments' => array('administer mailing lists'),
+    'type' => MENU_CALLBACK,
+    'file' => 'mailing_list.admin.inc',
+  );
 
   return $items;
 }
 
+/**
+ * Implementation of hook_block().
+ */
 function mailing_list_block($op = 'list', $delta = 0, $edit = array()) {
   $block = array();
   switch ($op) {
+    case 'configure':
+      $form['mailing_list_show_name_'. $delta] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Show name field in subscription form'),
+        '#default_value' => variable_get('mailing_list_show_name_'. $delta, 1),
+        '#description' => t('Whether or not to show a text field in the subscription form that this block displays, letting a subscriber enter his or her name. If the name field is shown, it also becomes required.'),
+      );
+      return $form;
+
+    case 'save':
+      variable_set('mailing_list_show_name_'. $delta, $edit['mailing_list_show_name_'. $delta]);
+
     case 'list':
       $query = "SELECT * FROM {mailing_list}";
       $result = db_query($query);
-      while ($row = db_fetch_object($result)) {
-        $block[$row->id] = array(
-          'info' => $row->list,
+      while ($list = db_fetch_object($result)) {
+        $block[$list->mlid] = array(
+          'info' => check_plain($list->name),
         );
       }
-    break;
+      break;
+
     case 'view':
-    $list = mailing_list_load($delta);
+      $list = mailing_list_load($delta);
       $block = array(
-        'subject' => $list->list ,
+        'subject' => check_plain($list->name),
         'content' => drupal_get_form('mailing_list_subscription_form', $list),
       );
-    break;
-
+      break;
   }
 
-
   return $block;
 }
-function mailing_list_subscription_form(&$form_state, $list ) {
-  $form = array();
-  $form['id']   = array(
-    '#type'       => 'hidden',
-    '#default_value' => $list->id,
-  );
-  $form['list']   = array(
-    '#type'       => 'hidden',
-    '#value'      => $list->list,
-  );
-  $form['email'] = array(
-    '#title'    => t('Email'),
-    '#type'     => 'textfield',
-    '#size'     => 20,
-  );
-  $form['submit'] = array(
-    '#value'      => t('Subscribe'),
-    '#type'       => 'submit',
-    '#submit'     => array('mailing_list_subscription_form_submit'),
-  );
-  $form['#validate'] = array('mailing_list_subscription_form_validate');
-  return $form;
-}
-function mailing_list_subscription_form_validate($form, &$form_state) {
-  $message = user_validate_mail($form_state['values']['email']);
-  if ($message) {
-    form_set_error('email', $message);
-  }
-}
-function mailing_list_subscription_form_submit($form, &$form_state) {
-  if ($form_state['values']['id'] == null) {
-    drupal_set_message('Error occured while saving your subscription. Please contact sie administrators', 'error');
-    return ;
-  }
-  $query = "INSERT INTO {mailing_list_emails} (mailing_list_id, email) VALUES (%d, '%s')";
-  if (db_query($query, $form_state['values']['id'], $form_state['values']['email'])) {
-    drupal_set_message('Your Subscription to <em>'. $form_state['values']['list'] .'</em> has been saved');
-  }
-  else {
-    drupal_set_message('Failed to subscribe to <em>'. $form_state['values']['list'] .'</em> please contact site administrators', 'error');
-  }
-}
-function mailing_list_load($id) {
-  $query = "SELECT * FROM {mailing_list} WHERE id = %d";
-  $return = db_fetch_object(db_query($query, $id));
+
+/**
+ * Return the mailing list object matching a mailing list ID.
+ *
+ * @param $mlid
+ *   The mailing list's ID.
+ *
+ * @return
+ *   The mailing list object, if exists, FALSE otherwise.
+ */
+function mailing_list_load($mlid) {
+  $query = "SELECT * FROM {mailing_list} WHERE mlid = %d";
+  $return = db_fetch_object(db_query($query, $mlid));
   return $return;
 }
-function mailing_list_admin() {
-  $output = '';
-  $output .= drupal_get_form('mailing_list_form');
-  $output .= mailing_list_lists();
-  return $output;
-}
-function mailing_list_lists() {
-  $query  = "SELECT * FROM {mailing_list}";
-  $result = db_query($query);
-  $rows = array();
-  while ($row = db_fetch_object($result)) {
-    $rows[] = $row->list . ' ' . l('edit', 'admin/settings/mailing-list/'. $row->id .'/edit') . ' ' . l('export' , 'mailing-list/' . $row->id . '/export');
-  }
 
-  return theme('item_list', $rows, "Available Mailing Lists");
+/**
+ * Return the mailing list e-mail object matching an e-mail ID.
+ *
+ * @param $eid
+ *   The e-mail's ID.
+ *
+ * @return
+ *   The mailing list e-mail object, if exists, FALSE otherwise.
+ */
+function mailing_list_email_load($eid) {
+  $query = "SELECT * FROM {mailing_list_emails} WHERE eid = %d";
+  $return = db_fetch_object(db_query($query, $eid));
+  return $return;
 }
 
-function mailing_list_export($list){
-
-	// --- set up file for export ---//
-
-		//get file directory
-		$path = file_directory_path();
-
-		//create file to hold email list
-		$filename = $list->list. '.csv';
-
-		//full path name
-		$full_path = $path.'/'.$filename;
-
-	// --- get email addresses from database ---//
-
-		//create query for selection of emails
-		$query = "SELECT * FROM {mailing_list_emails} WHERE mailing_list_id='%d'";
-
-		//run query
-		$result = db_query($query, $list->id);
-
-		//create string with all the emails
-		$emails = array();
-		while ($row = db_fetch_object($result)){
-			$emails[] = $row->email;
-		}
-
-		$emails = implode(",\n", $emails);
-
-		//write resultant string to file
-		file_save_data($emails, $full_path, FILE_EXISTS_REPLACE);
-
-		//set headers for file transfer
-		$headers = array(
-			'Content-Type: application/octet-stream',
-			'Content-Disposition: attachment; filename="' . basename($full_path) . '";',
-			'Content-Length: ' . sprintf('%u', filesize($full_path)),
-		);
-
-		file_transfer($full_path, $headers);
-
+/**
+ * Gets the name for a subscriber e-mail if available, otherwise gets the
+ * e-mail address.
+ *
+ * @param $data
+ *   Subscriber object.
+ *
+ * @return
+ *   Subscriber name or subscriber e-mail.
+ */
+function mailing_list_email_get_name($data) {
+  $data = (object)$data;
+  return !empty($data->name) ? $data->name : $data->mail;
 }
 
-function mailing_list_form(&$form_state, $list = null) {
-
+/**
+ * Display a form letting a user subscribe to a mailing list.
+ */
+function mailing_list_subscription_form(&$form_state, $list) {
   $form = array();
-  if ( isset($form_state['values']['id']) || isset($list) ) {
-    $form['id']   = array(
-      '#type'       => 'hidden',
-      '#value'      => isset($form_state['values']['id']) ? $form_state['values']['id'] : isset($list) ? $list->id: null,
+  $form['mlid'] = array(
+    '#type' => 'hidden',
+    '#default_value' => $list->mlid,
+  );
+  $form['ml_name'] = array(
+    '#type' => 'hidden',
+    '#value' => $list->name,
+  );
+  if (variable_get('mailing_list_show_name_'. $list->mlid, 1)) {
+    $form['name'] = array(
+      '#title' => t('Name'),
+      '#type' => 'textfield',
+      '#size' => 20,
+      '#required' => TRUE,
     );
   }
-  $form['form'] = array(
-    '#title'    => t('Create mailing list'),
-    '#type'     => 'fieldset',
-    '#collapsible'  => TRUE,
-    '#collapsed'    => FALSE,
-  );
-  $form['form']['list_name'] = array(
-    '#title'      => t('Mailing List Name'),
-    '#type'       => 'textfield',
-    '#required'   => TRUE,
-    '#default_value'=> isset($form_state['values']['list_name']) ? $form_state['values']['list_name']: isset($list)?$list->list:'',
+  else {
+    $form['name'] = array(
+      '#type' => 'hidden',
+      '#value' => '',
+    );
+  }
+  $form['mail'] = array(
+    '#title' => t('E-mail'),
+    '#type' => 'textfield',
+    '#size' => 20,
   );
-  $form['form']['submit'] = array(
-    '#value'      => t('Save'),
-    '#type'       => 'submit',
-    '#submit'     => array('mailing_list_form_submit'),
+  $form['submit'] = array(
+    '#value' => t('Subscribe'),
+    '#type' => 'submit',
+    '#submit' => array('mailing_list_subscription_form_submit'),
   );
-  $form['#redirect'] = 'admin/settings/mailing-list';
+  $form['#validate'] = array('mailing_list_subscription_form_validate');
   return $form;
 }
 
-function mailing_list_form_submit($form, &$form_state) {
-  if (isset($form_state['values']['id'])) {
-    $query = "UPDATE {mailing_list} SET list = '%s' WHERE id = %d";
-    $result = db_query($query, $form_state['values']['list_name'], $form_state['values']['id']);
+/**
+ * Validation handler for the subscription form; checks name and e-mail
+ * entered.
+ */
+function mailing_list_subscription_form_validate($form, &$form_state) {
+  if (variable_get('mailing_list_show_name_'. $form_state['values']['mlid'], 1) && empty($form_state['values']['name'])) {
+    form_set_error('name', t('Name is required.'));
   }
-  else {
-    $query = "INSERT INTO {mailing_list} (list) VALUES ('%s')";
-    $result = db_query($query, $form_state['values']['list_name']);
+  $message = user_validate_mail($form_state['values']['mail']);
+  if ($message) {
+    form_set_error('mail', $message);
   }
+  elseif (db_fetch_object(db_query("SELECT * FROM {mailing_list_emails} WHERE mlid = %d AND mail = '%s'", $form_state['values']['mlid'], $form_state['values']['mail']))) {
+    form_set_error('mail', t('The e-mail %mail already exists in mailing list %name.', array('%mail' => $form_state['values']['mail'], '%name' => $form_state['values']['ml_name'])));
+  }
+}
 
-  if ($result) {
-    if (isset($form_state['values']['id']) ) {
-      drupal_set_message('Updated Mailing List: '. check_plain($form_state['values']['list_name']));
-    }
-    else {
-      drupal_set_message('New Mailing List Created: '. check_plain($form_state['values']['list_name']));
-    }
+/**
+ * Submit handler for the subscription form; saves a subscription.
+ */
+function mailing_list_subscription_form_submit($form, &$form_state) {
+  if ($form_state['values']['mlid'] == null) {
+    drupal_set_message(t('Unable to save mailing list subscription: no mailing list specified.'), 'error');
+    return;
+  }
+  $query = "INSERT INTO {mailing_list_emails} (mlid, name, mail) VALUES (%d, '%s', '%s')";
+  if (db_query($query, $form_state['values']['mlid'], $form_state['values']['name'], $form_state['values']['mail'])) {
+    drupal_set_message(t('Subscription for %mail saved.', array('%mail' => $form_state['values']['mail'])));
+    watchdog('mailing_list', 'Mailing list: %name added via subscription form.', array('%name' => $form_state['values']['mail']));
   }
   else {
-    if (isset($form_state['values']['id'])) {
-      drupal_set_message('Failed to Update Mailing List: '. check_plain($form_state['values']['list_name']), 'error');
-    }
-    else {
-      drupal_set_message('Failed to Create New Mailing List: '. check_plain($form_state['values']['list_name']), 'error');
-    }
+    drupal_set_message(t('Failed to subscribe to mailing list %name.', array('%name' => $form_state['values']['ml_name'])), 'error');
   }
 }
