array( 'name' => t('Newsletter issue'), 'module' => 'simplenews', 'description' => t('Create a newsletter issue to be sent to subscribed e-mail addresses.'), ), ); } /** * Implementation of hook_perm(). */ function simplenews_perm() { return array('view links in block', 'create newsletter', 'edit own newsletter', 'edit any newsletter','administer newsletters', 'send newsletter', 'subscribe to newsletters'); } /** * Implementation of hook_access(). */ function simplenews_access($op, $node) { global $user; if ($op == 'create') { if (user_access('create newsletter') || user_access('administer newsletters')) { return TRUE; } } if ($op == 'update' || $op == 'delete') { if (user_access('administer newsletters')) { return TRUE; } elseif (user_access('edit any newsletter')) { return TRUE; } elseif (user_access('edit own newsletter') && $user->uid == $node->uid) { return TRUE; } } } /** * Implementation of hook_menu(). */ function simplenews_menu($may_cache) { $items = array(); $administer = user_access('administer newsletters'); if ($may_cache) { $items[] = array('path' => 'node/add/simplenews', 'title' => t('Newsletter issue'), 'access' => user_access('create newsletter'), ); $items[] = array( 'path' => 'admin/content/newsletters', 'title' => t('Newsletters'), 'type' => MENU_NORMAL_ITEM, 'description' => t('Manage newsletters, subscriptions, and configuration options.'), 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_news'), 'access' => $administer, ); $items[] = array('path' => 'admin/content/newsletters/sent', 'title' => t('Sent issues'), 'access' => $administer, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_news'), ); $items[] = array('path' => 'admin/content/newsletters/notsent', 'title' => t('Drafts'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -9, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_news', 'notsent'), ); $items[] = array('path' => 'admin/content/newsletters/types', 'title' => t('Newsletters'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -8, 'callback' => 'simplenews_types_overview', ); $items[] = array('path' => 'admin/content/newsletters/types/edit', 'title' => t('Newsletters'), 'access' => $administer, 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_types_form'), ); $items[] = array('path' => 'admin/content/newsletters/types/delete', 'title' => t('Newsletters'), 'access' => $administer, 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_types_delete'), ); $items[] = array('path' => 'admin/content/newsletters/types/list', 'title' => t('List newsletters'), 'access' => $administer, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items[] = array('path' => 'admin/content/newsletters/types/add', 'title' => t('Add newsletter'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -9, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_types_form'), ); $items[] = array( 'path' => 'admin/content/newsletters/subscriptions/delete', 'title' => t('Delete'), 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => 'simplenews_subscription_multiple_delete_confirm', 'access' => $administer, ); $items[] = array('path' => 'admin/content/newsletters/users', 'title' => t('Subscriptions'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -7, 'callback' => 'simplenews_subscription_admin', ); $items[] = array('path' => 'admin/content/newsletters/users/edit', 'title' => t('Subscriptions'), 'access' => $administer, 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_users_form'), ); $items[] = array('path' => 'admin/content/newsletters/users/delete', 'title' => t('Subscriptions'), 'access' => $administer, 'type' => MENU_CALLBACK, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_users_delete'), ); $items[] = array('path' => 'admin/content/newsletters/users/list', 'title' => t('List subscriptions'), 'access' => $administer, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items[] = array('path' => 'admin/content/newsletters/users/import', 'title' => t('Import subscriptions'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -9, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_subscription_list_add'), ); $items[] = array('path' => 'admin/content/newsletters/users/export', 'title' => t('Export subscriptions'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -8, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_subscription_list_export'), ); $items[] = array('path' => 'admin/content/newsletters/settings', 'title' => t('Settings'), 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => -6, 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_admin_settings'), ); $items[] = array('path' => 'admin/content/newsletters/settings/general', 'title' => t('General'), 'access' => $administer, 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items[] = array('path' => 'newsletter/confirm', 'title' => t('Confirm newsletter subscriptions'), 'access' => user_access('subscribe to newsletters'), 'callback' => 'simplenews_confirm_subscription', 'type' => MENU_CALLBACK, ); $items[] = array('path' => 'newsletter/subscriptions', 'title' => t('Manage newsletter subscriptions'), 'access' => user_access('subscribe to newsletters'), 'callback' => 'drupal_get_form', 'callback arguments' => array('simplenews_subscription_manager_form'), 'type' => MENU_CALLBACK, ); } else { drupal_add_css(drupal_get_path('module', 'simplenews') .'/simplenews.css', 'module', 'all', FALSE); if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'newsletters' && arg(3) == 'settings') { $tree = taxonomy_get_tree(variable_get('simplenews_vid', '')); if ($tree) { $weight = -9; foreach ($tree as $newsletter) { $items[] = array('path' => 'admin/content/newsletters/settings/'. $newsletter->tid, 'title' => $newsletter->name, 'access' => $administer, 'type' => MENU_LOCAL_TASK, 'weight' => $weight++, ); } } } /** * Always load simplenews_views.inc when views module is present */ if (module_exists('views')) { include_once(drupal_get_path('module', 'simplenews') .'/simplenews_views.inc'); } } return $items; } /** * Implementation of hook_form(). */ function simplenews_form(&$node) { $type = node_get_types('type', $node); global $user; if ($type->has_title) { $form['title'] = array( '#type' => 'textfield', '#title' => check_plain($type->title_label), '#default_value' => $node->title, '#size' => 60, '#maxlength' => 128, '#required' => TRUE, ); } if ($type->has_body) { $form['body_filter']['body'] = array( '#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => $node->body, '#rows' => 20, '#required' => ($type->min_word_count > 0), '#description' => t('This will be the body of your newsletter. Available variables are:') . ' %site ' . t('(the name of your website),') . ' %uri ' . t('(a link to your homepage),') . ' %uri_brief ' . t('(homepage link without the http://),') . ' %mymail ' . t('(your e-mail address),') . ' %date ' . t('(today\'s date),') . ' %login_uri ' . t('(link to login page).'), ); $form['body_filter']['format'] = filter_form($node->format); } if (!$sel1 = $node->s_format) { $sel1 = variable_get('simplenews_format', 'plain'); } if (!$sel2 = $node->priority) { $sel2 = variable_get('simplenews_priority', 0); } if (!$sel3 = $node->receipt) { $sel3 = variable_get('simplenews_receipt', 0); } $form['sending_options'] = array( '#type' => 'fieldset', '#title' => t('Newsletter sending options'), '#collapsible' => TRUE, '#collapsed' => FALSE, ); $form['sending_options']['s_format'] = array( '#type' => 'select', '#title' => t('Format'), '#default_value' => $sel1, '#options' => _simplenews_format_options(), ); $form['sending_options']['priority'] = array('#type' => 'select', '#title' => t('Priority'), '#default_value' => $sel2, '#options' => array(0 => t('none'), 1 => t('highest'), 2 => t('high'), 3 => t('normal'), 4 => t('low'), 5 => t('lowest')), ); $form['sending_options']['receipt'] = array('#type' => 'checkbox', '#title' => t('Request receipt'), '#return_value' => 1, '#default_value' => $sel3, ); if ($node->s_status == 0) { if (user_access('send newsletter')) { $options[0] = t("Don't send now"); $options[2] = t('Send one test newsletter to the test address'); $options[1] = t('Send newsletter'); $form['sending_options']['send'] = array( '#type' => 'radios', '#title' => t('Sending'), '#default_value' => $node->send ? $node->send : variable_get('simplenews_send', 0), '#options' => $options, ); } else { $options[0] = t("Don't send now"); $options[2] = t('Send one test newsletter to the test address'); $form['sending_options']['send'] = array('#type' => 'radios', '#title' => t('Sending'), '#default_value' => $node->send ? $node->send : 0, '#options' => $options, '#description' => t('You have no privileges to send this newsletter'), ); } if (variable_get('simplenews_test_address_override', 0)) { $form['sending_options']['test_address'] = array('#type' => 'textfield', '#title' => t('Test e-mail addresses'), '#default_value' => $node->test_address ? $node->test_address : variable_get('simplenews_test_address', ''), '#size' => 60, '#maxlength' => 128, ); $form['sending_options']['#description'] = t('Supply a comma-separated list of e-mail addresses to be used as test addresses.'); } } else { $atts = array('disabled' => 'disabled'); $form['sending_options']['none'] = array('#type' => 'checkbox', '#title' => t('This newsletter has been sent'), '#return_value' => 0, '#attributes' => array('checked' => 'checked', 'disabled' => 'disabled'), ); } $form['s_status'] = array('#type' => 'hidden', '#value' => $node->s_status ? $node->s_status : 0); return $form; } /** * Implementation of hook_validate(). */ function simplenews_validate($node) { global $valid_mails; if ($node->send == 1) { if (!isset($node->taxonomy)) { $names = node_get_types('names', $node); form_set_error('', t('You should select content type %content_type in !newsletter_vocabulary before you can send this newsletter.', array('%content_type' => $names[$node->type], '!newsletter_vocabulary' => l(t('Newsletter vocabulary'), 'admin/content/taxonomy/edit/vocabulary/'. variable_get('simplenews_vid', ''))))); } elseif (!simplenews_validate_taxonomy($node->taxonomy)) { form_set_error('taxonomy', t('You should select a newsletter before you can send this newsletter.')); } } elseif ($node->send == 2) { if (variable_get('simplenews_test_address_override', 0)) { $mails = explode(',',$node->test_address); } else { $mails = explode(',',variable_get('simplenews_test_address', '')); } foreach ($mails as $mail) { $mail = trim($mail); if ($mail == '') { form_set_error('', t('Cannot send test newsletter: no valid test e-mail address specified.')); } elseif (!valid_email_address($mail)) { form_set_error('', t('Cannot send test newsletter to %mail: e-mail address invalid.', array('%mail' => $mail))); } else { $valid_mails[] = $mail; } } } } /** * Implementation of hook_submit(). */ function simplenews_submit(&$node) { global $valid_mails; if ($node->send == 2 && $valid_mails) { $node->test_address = $valid_mails; } } function simplenews_validate_taxonomy($taxonomy) { $vid = variable_get('simplenews_vid', ''); $result = db_query('SELECT tid FROM {term_data} WHERE vid = %d', $vid); while ($tid = db_fetch_object($result)) { $tids[] = $tid->tid; } if (isset($tids) && !empty($taxonomy)) { $taxes = array(); foreach ($taxonomy as $tax) { $taxes[] = $tax; } $selected_terms = array_intersect($tids, $taxes); return empty($selected_terms) ? FALSE : $selected_terms; } return FALSE; } /** * Implementation of hook_cron(). */ function simplenews_cron() { _simplenews_send(FALSE); } /** * Implementation of hook_insert(). * Saves extra node content to module database table. */ function simplenews_insert($node) { $term = simplenews_validate_taxonomy($node->taxonomy); $tid = is_array($term) ? array_values($term) : FALSE; $node->simplenews_tid = $tid ? $tid[0] : 0; //tid is also saved in this table since it is needed by _simplenews_send(), and the term_node table is //only updated after the execution of simplenews_insert(). It cannot be passed by a variable //since simplenews_cron() also calls _simplenews_send(). $s_status = ($node->send == 1 && user_access('send newsletter')) ? 1 : 0; db_query("INSERT INTO {simplenews_newsletters} (nid, vid, tid, s_status, s_format, priority, receipt) VALUES (%d, %d, %d, %d, '%s', %d, %d)", $node->nid, $node->vid, $node->simplenews_tid, $s_status, $node->s_format, $node->priority, $node->receipt); } /** * Implementation of hook_update(). */ function simplenews_update($node) { $term = simplenews_validate_taxonomy($node->taxonomy); $tid = is_array($term) ? array_values($term) : FALSE; $node->simplenews_tid = $tid ? $tid[0] : 0; if ($node->send == 1 && user_access('send newsletter')) { db_query("UPDATE {simplenews_newsletters} SET vid = %d, tid = %d, s_status = %d, s_format = '%s', priority = %d, receipt = %d WHERE nid = %d", $node->vid, $node->simplenews_tid, 1, $node->s_format, $node->priority, $node->receipt, $node->nid); } else { db_query("UPDATE {simplenews_newsletters} SET tid = %d, s_format = '%s', priority = %d, receipt = %d WHERE nid = %d", $node->simplenews_tid, $node->s_format, $node->priority, $node->receipt, $node->nid); } } /** * Implementation of hook_nodeapi(). */ function simplenews_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { if ($node->type == 'simplenews' && ($op == 'update' || $op == 'insert')) { if ($node->send == 1) { _simplenews_send(TRUE); drupal_set_message(t('Newsletter %newsletter is being sent', array('%newsletter' => $node->title))); } elseif ($node->send == 2) { simplenews_send_test($node); } } } /** * Implementation of hook_delete(). */ function simplenews_delete($node) { $result = db_query('DELETE FROM {simplenews_newsletters} WHERE nid = %d', $node->nid); if ($result) { drupal_set_message(t('Newsletter %title was successfully deleted.', array('%title' => $node->title))); } } /** * Implementation of hook_load(). */ function simplenews_load($node) { return db_fetch_object(db_query('SELECT * FROM {simplenews_newsletters} WHERE nid = %d', $node->nid)); } /** * Implementation of hook_taxonomy(). * * Deletes subscriptions to term when term is deleted, and cleans the blocks * table. */ function simplenews_taxonomy($op, $type, $array = NULL) { if ($type == 'term' && $op == 'delete' && $array['vid'] == variable_get('simplenews_vid', '')) { db_query('DELETE FROM {simplenews_snid_tid} WHERE tid = %d', $array['tid']); db_query("DELETE FROM {blocks} WHERE module = '%s' AND delta = '%s'", 'simplenews', 'newsletter-'. $array['tid']); drupal_set_message(t('Deleted all subscriptions to newsletter %newsletter.', array('%newsletter' => $array['name']))); } elseif ($op == 'delete' && $type == 'vocabulary' && $array['vid'] == variable_get('simplenews_vid', '')) { variable_del('simplenews_vid'); } } /** * Implementation of hook_view(). */ function simplenews_view(&$node, $teaser = FALSE) { $node = simplenews_replace_vars($node, TRUE); $node = node_prepare($node, $teaser); return $node; } /** * Implementation of hook_form_alter(). */ function simplenews_form_alter($form_id, &$form) { $vid = variable_get('simplenews_vid', ''); // Newsletter vocabulary form if ($form_id == 'taxonomy_form_vocabulary' && isset($form['vid']) && $form['vid']['#value'] == $vid) { // Hide critical options from forum vocabulary. $form['help_forum_vocab'] = array( '#value' => t('This is the designated simplenews vocabulary. This vocabulary can not be deleted.'), '#weight' => -1, ); $form['nodes']['#required'] = TRUE; $form['nodes']['#description'] = t('Select content type(s) to be used as newsletter'); $form['multiple'] = array('#type' => 'value', '#value' => FALSE); // Prevent the vocabulary gets deleted unset($form['delete']); } } /** * Implementation of hook_user(). * * Checks whether an email address is subscribed to the newsletter when a new * user signs up. If so, changes uid from 0 to the new uid in * simplenews_subscriptions so that the user's subscription status is known when * he logs in. */ function simplenews_user($op, &$edit, &$account, $category = NULL) { switch ($op) { case 'insert': if ($edit['mail']) { $query = "SELECT snid FROM {simplenews_subscriptions} WHERE mail = '%s'"; if ($result = db_fetch_object(db_query($query, $edit['mail']))) { db_query("UPDATE {simplenews_subscriptions} SET uid = %d WHERE snid = %d", $edit['uid'], $result->snid); } } break; case 'update': if ($category == 'account' && $edit['mail']) { $query = "SELECT snid FROM {simplenews_subscriptions} WHERE uid = %d"; if ($result = db_fetch_object(db_query($query, $account->uid))) { db_query("DELETE FROM {simplenews_subscriptions} WHERE mail = '%s' AND uid = %d", $edit['mail'], 0); db_query("UPDATE {simplenews_subscriptions} SET mail = '%s' WHERE snid = %d", $edit['mail'], $result->snid); } else { $query = "SELECT snid FROM {simplenews_subscriptions} WHERE mail = '%s'"; if ($result = db_fetch_object(db_query($query, $edit['mail']))) { db_query("UPDATE {simplenews_subscriptions} SET uid = %d WHERE snid = %d", $account->uid, $result->snid); } } } // Activate/deactivate subscription when account is blocked/unblocked if ($category == 'account' && isset($edit['status'])) { if (variable_get('simplenews_sync_account', FALSE)) { db_query("UPDATE {simplenews_subscriptions} SET a_status = %d WHERE uid = %d", $edit['status'], $account->uid); } } if ($category == 'newsletter' && user_access('subscribe to newsletters')) { foreach($edit['newsletters'] as $tid => $checked) { if ($checked) { simplenews_subscribe_user($account->mail, $tid, FALSE); } else { simplenews_unsubscribe_user($account->mail, $tid, FALSE); } } } break; case 'delete': if (variable_get('simplenews_sync_account', FALSE)) { // Delete subscription and all newsletter subscriptions when account is removed $subscription = simplenews_get_user_subscription($account->mail); db_query('DELETE FROM {simplenews_snid_tid} WHERE snid = %d', $subscription->snid); db_query('DELETE FROM {simplenews_subscriptions} WHERE snid = %d', $subscription->snid); } else { // Only remove uid from subscription data when account is removed db_query("UPDATE {simplenews_subscriptions} SET uid = 0 WHERE uid = %d", $account->uid); } break; case 'form': if ($category == 'newsletter' && user_access('subscribe to newsletters')) { $subscription = simplenews_get_user_subscription($account->mail); $form = _simplenews_subscription_manager_form($subscription); $form['subscriptions']['#title'] = t('Current newsletter subscriptions'); unset($form['update'], $form['subscriptions']['mail']); return $form; } break; case 'categories': if (user_access('subscribe to newsletters')) { $output[] = array('name' => 'newsletter', 'title' => t('My newsletters'), 'weight' => 10); } return $output; case 'view': global $user; if ($user->uid == $account->uid || user_access('administer users')) { $tree = taxonomy_get_tree(variable_get('simplenews_vid', '')); foreach ($tree as $newsletter) { if (db_num_rows(db_query('SELECT s.uid FROM {simplenews_subscriptions} s INNER JOIN {simplenews_snid_tid} t ON s.snid = t.snid WHERE s.uid = %d AND t.tid = %d', $account->uid, $newsletter->tid))) { $subscriptions[] = l($newsletter->name, 'taxonomy/term/'. $newsletter->tid); } } if ($subscriptions) { $subscriptions = implode(', ', $subscriptions); } else { $subscriptions = t('Currently no subscriptions'); } $items[] = array('class' => 'item', 'title' => t('Current subscriptions'), 'value' => $subscriptions, ); if (user_access('subscribe to newsletters')) { $items[] = array('class' => 'item', 'title' => t('Manage subscriptions'), 'value' => l(t('My newsletters'), 'user/'. $account->uid .'/edit/newsletter'), ); } return array(t('Newsletters') => $items); } break; } } /** * Implementation of hook_block(). */ function simplenews_block($op = 'list', $delta = 0, $edit = array()) { list($type, $tid) = explode('-', $delta); switch ($op) { case 'list': $blocks = array(); foreach (taxonomy_get_tree(variable_get('simplenews_vid', '')) as $newsletter) { $blocks['newsletter-'. $newsletter->tid] = array('info' => t('Newsletter: @title', array('@title' => $newsletter->name))); } return $blocks; case 'configure': $form['simplenews_block_'. $delta]['simplenews_block_m_status_'. $tid] = array('#type' => 'checkbox', '#title' => t('Display block message'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_m_status_'. $tid, 1), ); $form['simplenews_block_'. $delta]['simplenews_block_m_'. $tid] = array('#type' => 'textfield', '#title' => t('Block message'), '#size' => 60, '#maxlength' => 128, '#default_value' => variable_get('simplenews_block_m_'. $tid, t('Stay informed on our latest news!')), ); $form['simplenews_block_'. $delta]['simplenews_block_f_'. $tid] = array('#type' => 'checkbox', '#title' => t('Display subscription form'), '#return_value' => 1, '#description' => t('If selected a subscription form is displayed, if not selected a link to the subscription page is displayed.'), '#default_value' => variable_get('simplenews_block_f_'. $tid, 1), ); $form['simplenews_block_'. $delta]['simplenews_block_l_'. $tid] = array('#type' => 'checkbox', '#title' => t('Display link to previous issues'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_l_'. $tid, 1), '#description' => t('Links (to previous issues, previous issues and RSS-feed) are only displayed to users who have "view links in block" privileges.'), ); $form['simplenews_block_'. $delta]['simplenews_block_i_status_'. $tid] = array('#type' => 'checkbox', '#title' => t('Display previous issues'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_i_status_'. $tid, 0), ); $form['simplenews_block_'. $delta]['simplenews_block_i_'. $tid] = array('#type' => 'select', '#title' => t('Number of issues to display'), '#options' => drupal_map_assoc(array(1,2,3,4,5,6,7,8,9,10)), '#default_value' => variable_get('simplenews_block_i_'. $tid, 5), ); $form['simplenews_block_'. $delta]['simplenews_block_r_'. $tid] = array('#type' => 'checkbox', '#title' => t('Display RSS-feed icon'), '#return_value' => 1, '#default_value' => variable_get('simplenews_block_r_'. $tid, 1), ); return $form; case 'save': variable_set('simplenews_block_m_status_'. $tid, $edit['simplenews_block_m_status_'. $tid]); variable_set('simplenews_block_m_'. $tid, $edit['simplenews_block_m_'. $tid]); variable_set('simplenews_block_f_'. $tid, $edit['simplenews_block_f_'. $tid]); variable_set('simplenews_block_l_'. $tid, $edit['simplenews_block_l_'. $tid]); variable_set('simplenews_block_i_status_'. $tid, $edit['simplenews_block_i_status_'. $tid]); variable_set('simplenews_block_i_'. $tid, $edit['simplenews_block_i_'. $tid]); variable_set('simplenews_block_r_'. $tid, $edit['simplenews_block_r_'. $tid]); break; case 'view': if ($type == 'newsletter') { if ($newsletter = taxonomy_get_term($tid)) { $block['subject'] = check_plain($newsletter->name); $block['content'] = theme('simplenews_block', _simplenews_block($newsletter->tid)); } } return $block; } } /** * Helper function: generate block content before theming * Collects data and applies access restriction */ function _simplenews_block($tid) { global $user; $block = array(); $recent = simplenews_recent_newsletters($tid, variable_get('simplenews_block_i_'. $tid, 5)); $block['subscribed'] = (simplenews_user_is_subscribed($user->mail, $tid) == TRUE); $block['user'] = !empty($user->uid); $block['tid'] = $tid; $block['message'] = check_plain(variable_get('simplenews_block_m_'. $tid, t('Stay informed on our latest news!'))); if (user_access('subscribe to newsletters')) { $block['form'] = drupal_get_form('simplenews_block_form', $tid); $block['subscription-link'] = l(t('Manage my subscriptions'), 'newsletter/subscriptions'); } if (user_access('view links in block') || user_access('administer newsletters')) { $block['newsletter-link'] = l(t('Previous issues'), 'taxonomy/term/'. $tid); $block['itemlist'] = theme('item_list', $recent, t('Previous issues'), 'ul'); $block['rssfeed'] = theme('feed_icon', url('taxonomy/term/'. $tid .'/0/feed')); } return $block; } /** * Simplenews themed block * Access restrictions have been applied. * $block contains all available data. See: _simplenews_block() */ function theme_simplenews_block($block) { $output = ''; if (variable_get('simplenews_block_m_status_'. $block['tid'], 1) && isset($block['message'])) { $output .= "

". $block['message'] ."

\n"; } if (variable_get('simplenews_block_f_'. $block['tid'], 1)) { $output .= $block['form']; } elseif (isset($block['subscription-link'])) { $output .= "

". $block['subscription-link']. "

\n"; } if (variable_get('simplenews_block_l_'. $block['tid'], 1) && isset($block['newsletter-link'])) { $output .= '\n"; } if (variable_get('simplenews_block_i_status_'. $block['tid'], 0) && isset($block['itemlist'])) { $output .= '
'. $block['itemlist'] ."
\n"; } if (variable_get('simplenews_block_r_'. $block['tid'], 1)) { $output .= $block['rssfeed'] ."\n"; } return $output; } /** * Helper function for API functions; loads a user or creates a dummy anonymous * user with uid = 0 and $mail equal to the input param. */ function _simplenews_user_load($mail) { $account = user_load(array('mail' => $mail)); if ($account === FALSE) { // Construct anonymous user since we don't have a user that matches that e-amil. $account = new StdClass(); $account->uid = 0; $account->mail = $mail; } return $account; } /** * API function; subscribes a user to a newsletter. * * @param $mail * The e-mail address to subscribe to the newsletter. * @param $tid * The term ID of the newsletter. * @param $confirm * Whether we should send a confirmation e-mail and hold off adding this user * to the newsletter until he or she clicks the confirm link in the e-mail. */ function simplenews_subscribe_user($mail, $tid, $confirm = TRUE) { //Prevent mismatches from accidental capitals in mail address $mail = strtolower($mail); $subscription = simplenews_get_user_subscription($mail); // If user is not subscribed to ANY newsletter, add basic info first. if (!$subscription) { $account = _simplenews_user_load($mail); db_query("INSERT INTO {simplenews_subscriptions} (mail, uid, a_status) VALUES ('%s', %d, 1)", $mail, $account->uid); $subscription = simplenews_get_user_subscription($mail); } $newsletter = taxonomy_get_term($tid); if ($confirm) { // Send confirmation e-mail to user to complete subscription or to tell // them that he or she is already subscribed. simplenews_mail_confirm($mail, $newsletter, $subscription ? $subscription->snid : NULL, 'subscribe'); } elseif (!isset($subscription->tids[$tid])) { // Then, add user to newsletter relationship if not already subscribed. db_query("INSERT INTO {simplenews_snid_tid} (snid, tid) VALUES (%d, %d)", $subscription->snid, $tid); } return TRUE; } /** * API function; unsubscribes a user from a newsletter. * * @param $mail * The e-mail address to unsubscribe from the newsletter. * @param $tid * The term ID of the newsletter. * @param $confirm * Whether we should send a confirmation e-mail and hold off removing this * user from the newsletter until he clicks the confirm link in the e-mail. */ function simplenews_unsubscribe_user($mail, $tid, $confirm = TRUE) { //Prevent mismatches from accidental capitals in mail address $mail = strtolower($mail); $subscription = simplenews_get_user_subscription($mail); if (!$newsletter = taxonomy_get_term($tid)) { watchdog('newsletter', t('Could not load newsletter term ID %id', array('%id' => $tid))); return FALSE; } if ($confirm) { // Send confirmation e-mail to user to complete unsubscription or to tell // them that he or she is not subscribed. simplenews_mail_confirm($mail, $newsletter, $subscription ? $subscription->snid : NULL, 'unsubscribe'); } elseif (isset($subscription->tids[$tid])) { // If we're not confirming first, just remove the user from the newsletter. db_query('DELETE FROM {simplenews_snid_tid} WHERE snid = %d AND tid = %d', $subscription->snid, $tid); // Clean up simplenews_subscriptions if no more newsletter subscriptions. if (!db_num_rows(db_query("SELECT tid FROM {simplenews_snid_tid} t WHERE t.snid = %d", $subscription->snid))) { db_query('DELETE FROM {simplenews_subscriptions} WHERE snid = %d', $subscription->snid); } } return TRUE; } /** * API function; returns if the user's e-mail address is subscribed to the given * newsletter. */ function simplenews_user_is_subscribed($mail, $tid) { $account = _simplenews_user_load($mail); return db_num_rows(db_query("SELECT * FROM {simplenews_subscriptions} s INNER JOIN {simplenews_snid_tid} t ON s.snid = t.snid WHERE s.mail = '%s' AND s.uid = %d AND t.tid = %d", $account->mail, $account->uid, $tid)) ? TRUE : FALSE; } /** * API function; returns the subscription for the given e-mail address. */ function simplenews_get_user_subscription($mail) { $account = _simplenews_user_load($mail); $snid = db_result(db_query("SELECT snid FROM {simplenews_subscriptions} s WHERE s.mail = '%s' AND s.uid = %d", $account->mail, $account->uid)); return simplenews_get_subscription($snid); } /** * API function; returns the subscription for the given subscription ID. */ function simplenews_get_subscription($snid) { $subscription = db_fetch_object(db_query("SELECT * FROM {simplenews_subscriptions} s WHERE s.snid = %d", $snid)); if ($subscription) { $result = db_query("SELECT tid FROM {simplenews_snid_tid} t WHERE t.snid = %d", $subscription->snid); $subscription->tids = array(); while ($newsletter = db_fetch_object($result)) { $subscription->tids[$newsletter->tid] = $newsletter->tid; } return $subscription; } else { return FALSE; } } function simplenews_handle_messages($one, $two_or_more, $type = 'status') { if (isset($_SESSION['messages'][$type])) $msg = $_SESSION['messages'][$type]; else $msg = array(); $key = array_search($one, $msg); if ($key || $key === 0) { $_SESSION['messages'][$type][$key] = $two_or_more; } elseif (!in_array($two_or_more, $msg)) { drupal_set_message($one, $type); } } /** * Generates the subscription form for users. */ function simplenews_subscription_manager_form($snid = NULL) { global $user; if (isset($snid)) { $subscription = simplenews_get_subscription($snid); // If we couldn't load subscription set defaults. if (!$subscription) { $subscription = new StdClass(); $subscription->tids = array(); } } else { $subscription = simplenews_get_user_subscription($user->mail); // If current user is not subscribed to any newsletter set current user data. if ($user->uid && !$subscription) { $subscription = new StdClass(); $subscription->tids = array(); $subscription->uid = $user->uid; $subscription->mail = $user->mail; } } // If non-admin is trying to edit someone else's subscription, access denied. if ($user->uid && $user->uid != $subscription->uid && !user_access('subscribe to newsletters')) { drupal_access_denied(); return; } $form = _simplenews_subscription_manager_form($subscription); return $form; } /** * Helper function to build subscription manager form, also used in user edit. */ function _simplenews_subscription_manager_form($subscription) { global $user; $form = array(); $form['#base'] = 'simplenews_subscription_manager_form'; $options = array(); foreach (taxonomy_get_tree(variable_get('simplenews_vid', '')) as $newsletter) { $options[$newsletter->tid] = $newsletter->name; } $form['subscriptions'] = array('#type' => 'fieldset', '#description' => t('Select the newsletter(s) to which you want to subscribe or unsubscribe.')); $form['subscriptions']['newsletters'] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => $subscription->tids, ); // If current user is an authenticated, just display e-mail. Anonymous users // see an e-mail box and will receive confirmations if ($user->uid) { $form['subscriptions']['#title'] = t('Subscriptions for %mail', array('%mail' => $subscription->mail)); $form['subscriptions']['mail'] = array('#type' => 'value', '#value' => $subscription->mail); $form['update'] = array('#type' => 'submit', '#value' => t('Update'), '#weight' => 20, ); } else { $form['subscriptions']['#title'] = t('Manage your newsletter subscriptions'); $form['subscriptions']['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#size' => 20, '#maxlength' => 128, '#weight' => 10, '#required' => TRUE, ); $form['subscribe'] = array('#type' => 'submit', '#value' => t('Subscribe'), '#weight' => 20, ); $form['unsubscribe'] = array('#type' => 'submit', '#value' => t('Unsubscribe'), '#weight' => 30, ); } return $form; } /** * Forms API callback; validates the settings form. */ function simplenews_subscription_manager_form_validate($form_id, $form_values) { $valid_email = valid_email_address($form_values['mail']); if (!$valid_email) { form_set_error('mail', t('The e-mail address you supplied is not valid.')); } $checked_newsletters = array_filter($form_values['newsletters']); if (!count($checked_newsletters) && !simplenews_get_user_subscription($form_values['mail'])) { form_set_error('newsletters', t('You must select at least one newsletter.')); } } /** * Forms API callback; submit handler for subscription form. */ function simplenews_subscription_manager_form_submit($form_id, $form_values) { switch ($form_values['op']) { case t('Update'): foreach($form_values['newsletters'] as $tid => $checked) { if ($checked) { simplenews_subscribe_user($form_values['mail'], $tid, FALSE); } else { simplenews_unsubscribe_user($form_values['mail'], $tid, FALSE); } } drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_values['mail']))); break; case t('Subscribe'): foreach($form_values['newsletters'] as $tid => $checked) { if ($checked) { simplenews_subscribe_user($form_values['mail'], $tid); } } drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.')); break; case t('Unsubscribe'): foreach($form_values['newsletters'] as $tid => $checked) { if ($checked) { simplenews_unsubscribe_user($form_values['mail'], $tid); } } drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete the unsubscription process.')); break; } // Return to home page unless we set the destination back to the admin page. return ''; } function simplenews_recent_newsletters($tid, $count = 5, $title = NULL) { $result = db_query_range(db_rewrite_sql('SELECT n.nid, n.title, sn.s_status FROM {node} n INNER JOIN {term_node} t ON n.nid = t.nid INNER JOIN {simplenews_newsletters} sn ON n.nid = sn.nid WHERE (t.tid = %d AND n.status = 1) ORDER BY n.created DESC'), $tid, 0, $count); $titles = array(); while ($item = db_fetch_object($result)) { $titles[$item->nid]['data'] = l($item->title, 'node/'. $item->nid); $titles[$item->nid]['class'] = ($item->s_status == 0) ? 'newsletter-created' : 'newsletter-send'; } return $titles; } /** * Show block subscription form. */ function simplenews_block_form($tid) { global $user; $form = array(); if ($user->uid) { if (simplenews_user_is_subscribed($user->mail, $tid)) { $submit_text = t('Unsubscribe'); $form['action'] = array('#type' => 'value', '#value' => 'unsubscribe'); } else { $submit_text = t('Subscribe'); $form['action'] = array('#type' => 'value', '#value' => 'subscribe'); } $form['display_mail'] = array( '#title' => t('User'), '#value' => check_plain($user->name), ); $form['mail'] = array('#type' => 'value', '#value' => $user->mail); } else { $form['mail'] = array('#type' => 'textfield', '#title' => t('E-mail'), '#size' => 20, '#maxlength' => 128, '#required' => TRUE, ); $form['action'] = array('#type' => 'radios', '#default_value' => 'subscribe', '#options' => array('subscribe' => t('Subscribe'), 'unsubscribe' => t('Unsubscribe')), ); } $form['tid'] = array('#type' => 'value', '#value' => $tid); $form['submit'] = array('#type' => 'submit', '#value' => isset($submit_text) ? $submit_text : t('Submit')); return $form; } /** * Forms API callback; handles block form (un)subscribe validation. */ function simplenews_block_form_validate($form_id, $form_values) { if (!valid_email_address($form_values['mail'])) { form_set_error('mail', t("The e-mail address you supplied is not valid.")); } } /** * Forms API callback; handles block form (un)subscribe submissions. */ function simplenews_block_form_submit($form_id, $form_values) { global $user; $account = _simplenews_user_load($form_values['mail']); // If e-mail belongs to the current registered user, don't send confirmation. $confirm = $account->uid && $account->uid == $user->uid ? FALSE : TRUE; switch ($form_values['action']) { case 'subscribe': simplenews_subscribe_user($form_values['mail'], $form_values['tid'], $confirm); if ($confirm) { drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.')); } else { drupal_set_message(t('You have been successfully subscribed.')); } break; case 'unsubscribe': simplenews_unsubscribe_user($form_values['mail'], $form_values['tid'], $confirm); if ($confirm) { drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete the unsubscription process.')); } else { drupal_set_message(t('You have been successfully unsubscribed.')); } break; } } /** * Prepare node for sending */ function simplenews_node_prepare($nid, $vid, $tid) { $node = node_load(array('nid' => $nid), $vid, TRUE); $node = simplenews_replace_vars($node, FALSE); // To play well with other modules that add content to the node, // simplenews_node_prepare() must mimic node_view() as far as possible. // Following is adapted from node_view(). $node = node_build_content($node, false, true); $content = drupal_render($node->content); $node->body = $content; unset($node->teaser); node_invoke_nodeapi($node, 'alter', false, true); $node = theme('simplenews_newsletter', $node, $tid); // TODO: Probably should refactor the whole processing, but check here for // mimemail and don't mess with body if we're gonna pass it to mimemail(). if ($node->s_format == 'plain' || !module_exists('mimemail')) { $node->body = simplenews_html_to_text($node->body, variable_get('simplenews_hyperlinks_'. $tid, 1)); } simplenews_set_from($node, $tid); return $node; } /** * Helper function to set from name and e-mail for a mail object. */ function simplenews_set_from(&$mail, $tid = NULL) { $address_default = variable_get('site_mail', ini_get('sendmail_from')); $name_default = variable_get('site_name', 'drupal'); if (isset($tid)) { $mail->from_address = variable_get('simplenews_from_address_'. $tid, $address_default); $mail->from_name = variable_get('simplenews_from_name_'. $tid, $name_default); } else { $mail->from_address = variable_get('simplenews_from_address', $address_default); $mail->from_name = variable_get('simplenews_from_name', $name_default); } } /** * Send the newsletter */ function _simplenews_send($timer = FALSE) { $max_time = variable_get('simplenews_time', 5); if ($timer && $max_time == 0) { return; } if ($max_time == 0) { $max_time = 1; } $max_time = $max_time - 0.5; $start_time = simplenews_time(); if (!$timer) { $throttle = variable_get('simplenews_throttle', 20); static $counter = 0; } $result = db_query(db_rewrite_sql('SELECT n.nid, s.vid, s.tid, n.created FROM {node} n INNER JOIN {simplenews_newsletters} s ON n.nid = s.nid WHERE s.s_status = %d ORDER BY n.created ASC'), 1); while ($nid = db_fetch_object($result)) { $term = taxonomy_get_term($nid->tid); $node = simplenews_node_prepare($nid->nid, $nid->vid, $nid->tid); $result2 = db_query('SELECT s.mail, s.snid FROM {simplenews_subscriptions} s INNER JOIN {simplenews_snid_tid} t ON s.snid = t.snid WHERE s.s_status = %d AND s.a_status = %d AND t.tid = %d ORDER BY s.snid ASC', 0, 1, $nid->tid); while ($mail = db_fetch_object($result2)) { $hash = _simplenews_generate_hash($mail->mail, $mail->snid, $nid->tid); // Add themable footer to message as this changes per user. $user_node = drupal_clone($node); $user_node->to = $mail->mail; $user_node = theme('simplenews_newsletter_footer', $user_node, $hash); $counter++; if (simplenews_mail_send($user_node)) { // TODO: This looks like it may choke if you were sending multiple // newsletters through cron. Should move s_status to snid_tid table // or somewhere else to see which newsletter has been sent. db_query('UPDATE {simplenews_subscriptions} SET s_status = %d WHERE snid = %d', 1, $mail->snid); // don't send mails too fast, servers may choke. Wait for 10 ms. usleep(10000); } else { watchdog('newsletter', t('Newsletter %title could not be sent to %email.', array('%title'=> $user_node->title, '%email' => $mail->mail)), WATCHDOG_ERROR); } if ($timer) { $int_time = simplenews_time(); } else { if ($counter < $throttle) { $int_time = $start_time; } else { return; } } if (!($int_time - $start_time < $max_time)) { return; } } db_query('UPDATE {simplenews_subscriptions} SET s_status = %d', 0); db_query('UPDATE {simplenews_newsletters} SET s_status = %d WHERE nid = %d', 2, $node->nid); if ($timer) { $int_time = simplenews_time(); } else { $int_time = $start_time; } if (!($int_time - $start_time < $max_time)) { return; } } } /** * Send a test newsletter */ function simplenews_send_test($input) { $tid = db_result(db_query('SELECT tid FROM {simplenews_newsletters} WHERE nid = %d', $input->nid)); $tid = $tid ? $tid : FALSE; $node = simplenews_node_prepare($input->nid, NULL, $tid); $term = $tid ? taxonomy_get_term($tid) : FALSE; $name = $term ? $term->name : 'Unassigned newsletter'; $node->body .= "\n\n-- \n". t('Footer will be appended here'); $recipients = $input->test_address; foreach ($recipients as $to) { $node->to = $to; if (simplenews_mail_send($node)) { drupal_set_message(t('Test newsletter sent to %recipient.', array('%recipient' => $to))); } } } /** * Send confirmation email */ function simplenews_mail_confirm($email, $newsletter, $snid = NULL, $op = NULL) { if (isset($snid) && isset($newsletter->tid)) { $hash = _simplenews_generate_hash($email, $snid, $newsletter->tid); } else { $hash = NULL; } $mail = theme('simplenews_newsletter_confirmation', $email, $newsletter, $snid, $op, $hash); if (simplenews_mail_send($mail)) { watchdog('newsletter', t('Sent confirmation e-mail to %mail.', array('%mail' => $email))); } else { watchdog('newsletter', t('Sending of confirmation e-mail to %mail failed.', array('%mail' => $email)), WATCHDOG_ERROR); } } /** * Mail engine to send newsletter. If you want to send HTML newsletters you need * to plug in an extra module * * @param $mail * An object with at least $mail->to, $mail->subject, and $mail->message. */ function simplenews_mail_send($mail) { $from_email = isset($mail->from_address) ? $mail->from_address : variable_get('site_mail', ini_get('sendmail_from')); $from = isset($mail->from_name) ? '"'. mime_header_encode(addslashes($mail->from_name)).'" <'. $from_email .'>' : $from_email; $headers = array( //'From' => $from, 'Reply-To' => $from_email, 'X-Mailer' => 'Drupal', 'Return-Path' => $from_email, 'Errors-To' => $from_email, ); // If receipt is requested, add headers. if ($mail->receipt){ $headers['Disposition-Notification-To'] = $from_email; $headers['X-Confirm-Reading-To'] = $from_email; } // Add priority if set. switch($mail->priority) { case 1: $headers['Priority'] = 'High'; $headers['X-Priority'] = '1'; $headers['X-MSMail-Priority'] = 'Highest'; break; case 2: $headers['Priority'] = 'urgent'; $headers['X-Priority'] = '2'; $headers['X-MSMail-Priority'] = 'High'; break; case 3: $headers['Priority'] = 'normal'; $headers['X-Priority'] = '3'; $headers['X-MSMail-Priority'] = 'Normal'; break; case 4: $headers['Priority'] = 'non-urgent'; $headers['X-Priority'] = '4'; $headers['X-MSMail-Priority'] = 'Low'; break; case 5: $headers['Priority'] = 'non-urgent'; $headers['X-Priority'] = '5'; $headers['X-MSMail-Priority'] = 'Lowest'; break; } // If subject is not set, default to title. if (!isset($mail->subject)) { $mail->subject = $mail->title; } if (module_exists('mimemail')) { if ($mail->s_format == 'plain') { $plain_text_only = TRUE; $plain_text_body = $mail->body; } else { $plain_text_only = FALSE; $plain_text_body = NULL; } return mimemail($from, $mail->to, $mail->subject, $mail->body, $plain_text_only, $headers, $plain_text_body); } else { return drupal_mail('simplenews-send-mail', $mail->to, $mail->subject, $mail->body, $from_email, $headers); } } /** * Other module-specific functions */ function simplenews_html_to_text($txt, $inline) { $pattern = '@(]*>(.+?))@ei'; if ($inline) { $txt = preg_replace($pattern, "_simplenews_mail_uri('\\2', '\\3')", $txt); } else { $txt = preg_replace($pattern, "'\\3 ['. _simplenews_mail_urls('\\2') .']'", $txt); $urls = _simplenews_mail_urls(); if (count($urls)) { $txt .= "\n"; $i = 0; for ($max = count($urls); $i < $max; $i++) { $txt .= '['. ($i + 1) .'] '. $urls[$i] ."\n"; } } _simplenews_mail_urls(0, TRUE); } // some basic html to text conversion $txt = preg_replace(_simplenews_define_search(), _simplenews_define_replace(), $txt); $txt = preg_replace("/\n\s+\n/", "\n\n", $txt); $txt = strip_tags($txt); $txt = decode_entities($txt); return wordwrap($txt, 80); } function _simplenews_mail_uri($href, $link) { $href = _simplenews_mail_url($href); if ($href == $link) { $output = '[ '. $href.' ]'; } else { $output = $link.' [ '. $href.' ]'; } return $output; } function _simplenews_mail_url($url) { if (preg_match('@://@', $url)) { return $url; } elseif (preg_match('!mailto:!i', $url)) { return str_replace('mailto:', '', $url); } else { return url($url, NULL, NULL, 1); } } function _simplenews_mail_urls($url = 0, $refresh = FALSE) { static $urls = array(); if($refresh) { $urls = array(); } if ($url) { $urls[] = _simplenews_mail_url($url); return count($urls); } return $urls; } /** * List of preg* regular expression patterns to search for, * used in conjunction with $replace. * Based on / modified from html2txt.module */ function _simplenews_define_search() { $search = array( "/\r/", // Non-legal carriage return "/[\t]+/", // tabs '/]*>.*?<\/script>/i', //