/[drupal]/contributions/modules/mass_contact/mass_contact.module
ViewVC logotype

Contents of /contributions/modules/mass_contact/mass_contact.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.17 - (show annotations) (download) (as text)
Thu Jul 31 18:17:05 2008 UTC (15 months, 4 weeks ago) by oadaeh
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +24 -20 lines
File MIME type: text/x-php
#289229 by ulf1: corrected ['Bcc'] to ['headers']['Bcc']. Also, commented out references to Mime Mail, and corrected the use of db_placeholders().
1 <?php
2 // $Id: mass_contact.module,v 1.16 2008/07/29 22:47:52 oadaeh Exp $
3
4 /**
5 * @file
6 * This is the main code file for the Mass Contact module. This module
7 * enables users to contact multiple users through selected roles.
8 */
9
10
11 /* ************************************************
12 *
13 * Functions for implementing various Drupal hooks.
14 *
15 * ***********************************************/
16
17
18 /**
19 * Implementation of hook_help().
20 * http://api.drupal.org/api/function/hook_help
21 *
22 * @param path
23 * The menu router path the help is being requested for.
24 * @param arg
25 * An array that corresponds to the return of the arg() function.
26 * @return
27 * A localized string containing the help text.
28 */
29 function mass_contact_help($path, $arg) {
30 $output = '';
31 switch ($path) {
32 case 'admin/help#mass_contact':
33 $output .= '<p><b>'. t('Related tasks:') .'</b><br /><ol>'.
34 '<li>' . l('Set Permissions', 'admin/user/permissions', array('fragment' => 'module-mass_contact')) .'</li>'.
35 '<li>' . l('List current categories', 'admin/build/mass_contact') .'</li>'.
36 '<li>' . l('Add new category', 'admin/build/mass_contact/add') .'</li>'.
37 '<li>' . l('Configure the module', 'admin/build/mass_contact/settings') .'</li>'.
38 '<li>' . l('Send mass e-mail', 'mass_contact') .'</li></ol>';
39 $output .= '<p>'. t('The Mass Contact module is simply a modified version of the core contact module. It works opposite the latter, in that it allows site moderators (or anyone with permission), to <a href="mass_contact">send mass e-mail</a> to a set role or group of roles or even to all registered users.') .'</p>';
40 $output .= '<p>'. t("The sender's own address may be placed in the 'To:' field and all recipients placed in the 'BCC:' field, or the recipients simply placed in the 'To:' field. Note that the latter option leaves all recipients open to abuse due to their e-mail addresses being visible to all other recipients.") .'</p>';
41 $output .= '<p>'. t("The e-mail may be sent as HTML or plain text, and may include a single binary file attachment (if permitted by admin).") .'</p>';
42 $output .= '<p>'. t("At the option of the sender (if permitted by admin), a node may be created in order to keep a record of the e-mail sent. Do not try to send e-mails by creating nodes; it will not work.") .'</p>';
43 $output .= '<p>'. t('Users may opt-out of mass mailings on their profile page, but this may be overridden by the admin (or respected). The entire opt-out system may be disabled on the <a href="@settings-page">settings page</a>.', array('@settings-page' => url('admin/build/mass_contact/settings'))) .'</p>';
44 $output .= '<p>'. t('Make sure to add at least one category and configure the module before trying to send mass e-mails.') .'</p>';
45
46 if (!module_exists('menu')) {
47 $menu_note = t('The menu item can be customized and configured only once the menu module has been <a href="@modules-page">enabled</a>.', array('@modules-page' => url('admin/build/modules')));
48 }
49 else {
50 $menu_note = '';
51 }
52
53 $output .= '<p>'. t('The Mass Contact module also adds a <a href="@menu-settings">menu item</a> (disabled by default) to the navigation block.', array('@menu-settings' => url('admin/build/menu'))) .' '. $menu_note .'</p>';
54 return ($output);
55 }
56 } // End of mass_contact_help().
57
58
59
60 /**
61 * Implementation of hook_perm().
62 * http://api.drupal.org/api/function/hook_perm
63 *
64 * @return
65 * An array of permissions strings.
66 */
67 function mass_contact_perm() {
68 $permissions = array('administer mass contact', 'choose whether to archive mass contact messages', 'create mass_contact content', 'send mass contact attachments', 'send mass contact e-mails');
69
70 $result = db_query('SELECT category FROM {mass_contact}');
71 while ($category = db_fetch_object($result)) {
72 $permissions[] = 'send to users in the '. $category->category .' category';
73 }
74
75 return $permissions;
76 } // End of mass_contact_perm().
77
78
79
80 /**
81 * Implementation of hook_menu().
82 * http://api.drupal.org/api/function/hook_menu
83 *
84 * @return
85 * An array of menu items.
86 */
87 function mass_contact_menu() {
88 $items = array();
89
90 $items['admin/build/mass_contact'] = array(
91 'title' => 'Mass Contact form',
92 'page callback' => 'mass_contact_admin_categories',
93 'access arguments' => array('administer mass contact'),
94 'description' => 'Create a mass contact form and set up categories for the form to use.',
95 );
96 $items['admin/build/mass_contact/list'] = array(
97 'title' => 'Category list',
98 'page callback' => 'mass_contact_admin_categories',
99 'access arguments' => array('administer mass contact'),
100 'type' => MENU_DEFAULT_LOCAL_TASK,
101 );
102 $items['admin/build/mass_contact/add'] = array(
103 'title' => 'Add category',
104 'page callback' => 'drupal_get_form',
105 'page arguments' => array('mass_contact_admin_edit'),
106 'access arguments' => array('administer mass contact'),
107 'type' => MENU_LOCAL_TASK,
108 'weight' => 1,
109 );
110 $items['admin/build/mass_contact/edit'] = array(
111 'title' => 'Edit Mass Contact category',
112 'page callback' => 'drupal_get_form',
113 'page arguments' => array('mass_contact_admin_edit'),
114 'access arguments' => array('administer mass contact'),
115 'type' => MENU_CALLBACK,
116 );
117 $items['admin/build/mass_contact/delete'] = array(
118 'title' => 'Delete Mass Contact category',
119 'page callback' => 'drupal_get_form',
120 'page arguments' => array('mass_contact_admin_delete'),
121 'access arguments' => array('administer mass contact'),
122 'type' => MENU_CALLBACK,
123 );
124 $items['admin/build/mass_contact/settings'] = array(
125 'title' => 'Settings',
126 'page callback' => 'drupal_get_form',
127 'page arguments' => array('mass_contact_admin_settings'),
128 'access arguments' => array('administer mass contact'),
129 'type' => MENU_LOCAL_TASK,
130 'weight' => 2,
131 );
132 $items['mass_contact'] = array(
133 'title' => 'Mass Contact',
134 'page callback' => 'mass_contact_site_page',
135 'access arguments' => array('send mass contact e-mails'),
136 'type' => MENU_SUGGESTED_ITEM,
137 );
138
139 return $items;
140 } // End of mass_contact_menu().
141
142
143
144 /**
145 * Implementation of hook_menu_alter().
146 * http://api.drupal.org/api/function/hook_menu_alter
147 *
148 * @param callbacks
149 * Associative array of menu router definitions returned from hook_menu().
150 */
151 function mass_contact_menu_alter(&$callbacks) {
152 $callbacks['node/add/mass-contact']['access callback'] = FALSE;
153 }
154
155
156
157 /**
158 * Implementation of hook_user().
159 * http://api.drupal.org/api/function/hook_user
160 *
161 * Provide form element to opt in to content mailouts.
162 *
163 * @param type
164 * The type of action being performed.
165 * @param edit
166 * The array of form values submitted by the user.
167 * @param user
168 * The user object on which the operation is being performed.
169 * @param category
170 * The active category of user information being edited.
171 */
172 function mass_contact_user($type, $edit, &$user, $category = NULL) {
173 if (variable_get('mass_contact_optout_d', 0) == 1) {
174 if ($type == 'register' || ($type == 'form' && $category == 'account')) {
175 $form['mail'] = array(
176 '#type' => 'fieldset',
177 '#title' => t('Group e-mail settings'),
178 '#weight' => 5,
179 '#collapsible' => TRUE,
180 );
181 $form['mail']['mass_contact_optout'] = array(
182 '#type' => 'checkbox',
183 '#title' => t('Opt-out of Mass E-mails'),
184 '#default_value' => $edit['mass_contact_optout'],
185 '#description' => t('Allows you to opt-out of group e-mails from privileged users. Note that site administrators are able to include you in mass e-mails even if you choose not to enable this feature, and the ability to opt-out may be removed by the administrator at any time.'),
186 );
187 return $form;
188 }
189 elseif ($type == 'validate') {
190 return array('mass_contact_optout' => $edit['mass_contact_optout']);
191 }
192 }
193 } // End of mass_contact_user().
194
195
196
197 /**
198 * Implementation of hook_nodeapi().
199 * http://api.drupal.org/api/function/hook_nodeapi
200 *
201 * @param node
202 * The node the action is being performed on.
203 * @param op
204 * The action that is being performed.
205 * @param a3
206 * The third argument. Has specific functions based on $op.
207 * @param a4
208 * The fourth argument. Has specific functions based on $op.
209 * @return
210 * Varies depending on the operation.
211 */
212 function mass_contact_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
213 // If this is a delete operation and the node type is mass_contact, then
214 // check for an attachment and delete the file if one exists.
215 if ($op == 'delete' && $node->type == 'mass_contact') {
216 // Look for the key phrase in the node body. If it exists, then there is
217 // an attachment that needs to be deleted.
218 $offset1 = strpos($node->body, '<hr>Attachment:<br />');
219 if ($offset1) {
220
221 // Using the saved attachment path, find the file name.
222 $file_location = variable_get('mass_contact_attachment_location', file_directory_path() .'/mass_contact_attachments');
223 $file_location_start = strpos($node->body, $file_location, $offset1);
224 if ($file_location_start) {
225 // Get the attachment file name.
226 $file_location_end = strpos($node->body, '">', $file_location_start);
227 $file_path_name = drupal_substr($node->body, $file_location_start, $file_location_end - $file_location_start);
228
229 if (file_exists($file_path_name)) {
230 if (!file_delete($file_path_name)) {
231 // Log an error.
232 watchdog('mass_contact', 'There was an error deleting the attachment.', WATCHDOG_ERROR);
233 }
234 }
235 else {
236 // Log an error.
237 watchdog('mass_contact', 'There was an indication of an attachment within the node body, but the attachment was not found. If the attachment is still there, it was NOT deleted.', WATCHDOG_WARNING);
238 }
239 }
240 else {
241 // Log an error.
242 watchdog('mass_contact', 'There was an indication of an attachment within the node body, but the attachment path was not found. If the attachment is still there, it was NOT deleted.', WATCHDOG_WARNING);
243 }
244 }
245 }
246 } // End of mass_contact_nodeapi().
247
248
249
250 /**
251 * Implementation of hook_mail().
252 * http://api.drupal.org/api/function/hook_mail
253 *
254 * @param key
255 * An identifier of the mail.
256 * @param message
257 * An array to be filled in. Keys in this array include: mail_id, to, subject, body, from & headers.
258 * @param params
259 * An arbitrary array of parameters set by the caller to drupal_mail.
260 */
261 function mass_contact_mail($key, &$message, $params) {
262 if (!empty($params['headers'])) {
263 foreach ($params['headers'] as $key => $value) {
264 $message['headers'][$key] = $params['headers'][$key];
265 }
266 }
267 $message['subject'] = $params['subject'];
268 $message['body'] = $params['body'];
269 } // End of mass_contact_mail().
270
271
272
273 /* **************************************************************
274 *
275 * Functions for listing, adding/editing and deleting categories.
276 *
277 * *************************************************************/
278
279
280
281 /**
282 * Displays a list of all existing categories.
283 *
284 * @return
285 * The themed page listing all current categories.
286 */
287 function mass_contact_admin_categories() {
288 $result = db_query("SELECT cid, category, recipients, selected FROM {mass_contact}");
289 $rows = array();
290 while ($category = db_fetch_object($result)) {
291 $rolenamesa = array();
292 foreach (explode(',', $category->recipients) as $rid) {
293 $namerole = db_fetch_object(db_query("SELECT name FROM {role} WHERE rid = %d", $rid));
294 $rolenamesa[] = ($namerole->name);
295 }
296 $rolenames = implode(', ', $rolenamesa);
297 $rows[] = array($category->category, $rolenames, ($category->selected ? t('Yes') : t('No')), l(t('edit'), 'admin/build/mass_contact/edit/'. $category->cid), l(t('delete'), 'admin/build/mass_contact/delete/'. $category->cid));
298 }
299 $header = array(t('Category'), t('Recipients'), t('Selected'), array('data' => t('Operations'), 'colspan' => 2));
300
301 return theme('table', $header, $rows);
302 } // End of mass_contact_admin_categories().
303
304
305
306 /**
307 * Displays a form to add or edit a category.
308 *
309 * @param form_state
310 * A keyed array containing the current state of the form.
311 * @param cid
312 * The id of the category to edit. If NULL, then add rather than edit.
313 * @return
314 * An associative array that defines the form to be built.
315 */
316 function mass_contact_admin_edit($form_state, $cid = NULL) {
317 $edit = array('category' => '', 'recipients' => '', 'selected' => '', 'cid' => '');
318
319 if (arg(3) == "edit" && $cid > 0) {
320 $edit = db_fetch_array(db_query("SELECT * FROM {mass_contact} WHERE cid = %d", $cid));
321 }
322
323 $form['category'] = array(
324 '#type' => 'textfield',
325 '#title' => t('Category'),
326 '#maxlength' => 255,
327 '#default_value' => $edit['category'],
328 '#description' => t("Will appear in the subject of your e-mail as [category]."),
329 '#required' => TRUE,
330 );
331
332 // get all roles except anonymous
333 $allroles = db_query("SELECT rid, name FROM {role} WHERE rid > %d", 1);
334 while ($roleobj = db_fetch_object($allroles)) {
335 $onerid = $roleobj->rid;
336 $onename = $roleobj->name;
337 $rolesarray[$onerid] = $onename;
338 }
339
340 $form['recipients'] = array(
341 '#type' => 'checkboxes',
342 '#title' => t('Roles to receive e-mail'),
343 '#options' => $rolesarray,
344 '#default_value' => explode(',', $edit['recipients']),
345 '#description' => t('These roles will be added to the mailing list. Note: if you check "authenticated users", other roles will not be added, as they will receive the e-mail anyway.'),
346 );
347
348 $form['selected_categories'] = array(
349 '#type' => 'fieldset',
350 '#title' => t('Selected categories'),
351 );
352 $form['selected_categories']['selected'] = array(
353 '#type' => 'select',
354 '#title' => t('Selected'),
355 '#options' => array('0' => t('No'), '1' => t('Yes')),
356 '#default_value' => $edit['selected'],
357 '#description' => t('Set this to <em>Yes</em> if you would like this category to be selected by default.'),
358 );
359 $form['selected_categories']['reset_selected'] = array(
360 '#type' => 'checkbox',
361 '#title' => t('Reset all previously selected categories to <em>No</em>.'),
362 );
363
364 $form['cid'] = array(
365 '#type' => 'value',
366 '#value' => $edit['cid'],
367 );
368
369 $form['submit'] = array(
370 '#type' => 'submit',
371 '#value' => t('Save'),
372 );
373
374 return $form;
375 } // End of mass_contact_admin_edit().
376
377
378
379 /**
380 * Validates the submission of the category add/edit page.
381 *
382 * @param form
383 * An associative array containing the structure of the form.
384 * @param form_state
385 * A keyed array containing the current state of the form.
386 */
387 function mass_contact_admin_edit_validate($form, &$form_state) {
388 $recipients = $form_state['values']['recipients'];
389 foreach ($recipients as $checkr) {
390 if ($checkr > 1) {
391 return;
392 }
393 }
394 form_set_error('recipients', t('You must check one or more recipients.'));
395 } // End of mass_contact_admin_edit_validate().
396
397
398
399 /**
400 * Processes the adding or editing of a category.
401 *
402 * @param form
403 * An associative array containing the structure of the form.
404 * @param form_state
405 * A keyed array containing the current state of the form.
406 */
407 function mass_contact_admin_edit_submit($form, &$form_state) {
408 if ($form_state['values']['reset_selected']) {
409 // Unselect all other contact categories.
410 db_query("UPDATE {mass_contact} SET selected = %d", 0);
411 }
412
413 // Remove 0s for unselected roles, convert to csv.
414 $recipients = $form_state['values']['recipients'];
415
416 // If all authenticated users are already added, remove all roles.
417 if ($recipients[2] == 2) {
418 foreach ($recipients as $checkr) {
419 if ($checkr > 2) {
420 $recipients[$checkr] = 0;
421 }
422 }
423 }
424
425 // Remove roles that were not selected.
426 foreach ($recipients as $recip) {
427 if ($recip != 0) {
428 $newformrec[] = $recip;
429 }
430 }
431 $form_state['values']['recipients'] = implode(',', $newformrec);
432
433 if (!isset($form_state['values']['reply'])) {
434 $form_state['values']['reply'] = '';
435 }
436 if (!isset($form_state['values']['weight'])) {
437 $form_state['values']['weight'] = 0;
438 }
439
440 if (arg(3) == 'add') {
441 db_query("INSERT INTO {mass_contact} (category, recipients, reply, weight, selected) VALUES ('%s', '%s', '%s', %d, %d)", $form_state['values']['category'], $form_state['values']['recipients'], $form_state['values']['reply'], $form_state['values']['weight'], $form_state['values']['selected']);
442 drupal_set_message(t('Category %category has been added.', array('%category' => $form_state['values']['category'])));
443 watchdog('mass_contact', 'Mass Contact form: category %category added.', array('%category' => $form_state['values']['category']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mass_contact'));
444 }
445 else {
446 db_query("UPDATE {mass_contact} SET category = '%s', recipients = '%s', reply = '%s', weight = %d, selected = %d WHERE cid = %d", $form_state['values']['category'], $form_state['values']['recipients'], $form_state['values']['reply'], $form_state['values']['weight'], $form_state['values']['selected'], $form_state['values']['cid']);
447 drupal_set_message(t('Category %category has been updated.', array('%category' => $form_state['values']['category'])));
448 watchdog('mass_contact', 'Mass Contact form: category %category updated.', array('%category' => $form_state['values']['category']), WATCHDOG_NOTICE, l(t('view'), 'admin/build/mass_contact'));
449 }
450
451 $form_state['redirect'] = 'admin/build/mass_contact';
452 } // End of mass_contact_admin_edit_submit().
453
454
455
456 /**
457 * Displays a form to select a category to delete.
458 *
459 * @param form_state
460 * A keyed array containing the current state of the form.
461 * @param cid
462 * The id of the category to delete.
463 * @return
464 * A confirmation form for the user to acknowledge.
465 */
466 function mass_contact_admin_delete($form_state, $cid = NULL) {
467 if ($info = db_fetch_object(db_query("SELECT category FROM {mass_contact} WHERE cid = %d", $cid))) {
468 $form['category'] = array(
469 '#type' => 'value',
470 '#value' => $info->category,
471 );
472
473 return confirm_form($form, t('Are you sure you want to delete %category?', array('%category' => $info->category)), 'admin/build/mass_contact', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
474 }
475 else {
476 drupal_set_message(t('Category not found.'), 'error');
477 drupal_goto('admin/build/mass_contact');
478 }
479 } // End of mass_contact_admin_delete().
480
481
482
483 /**
484 * Does the actual deleting of the category.
485 *
486 * @param form
487 * An associative array containing the structure of the form.
488 * @param form_state
489 * A keyed array containing the current state of the form.
490 */
491 function mass_contact_admin_delete_submit($form, &$form_state) {
492 db_query("DELETE FROM {mass_contact} WHERE cid = %d", arg(4));
493 drupal_set_message(t('Category %category has been deleted.', array('%category' => $form_state['values']['category'])));
494 watchdog('mass_contact', 'Mass Contact form: category %category deleted.', array('%category' => $form_state['values']['category']));
495 $form_state['redirect'] = 'admin/build/mass_contact';
496 } // End of mass_contact_admin_delete_submit().
497
498
499
500 /* ***********************************************
501 *
502 * Functions for handling administtative settings.
503 *
504 * **********************************************/
505
506
507
508 /**
509 * Administration settings form.
510 *
511 * @param form_state
512 * A keyed array containing the current state of the form.
513 * @return
514 * An associative array that defines the form to be built.
515 */
516 function mass_contact_admin_settings($form_state) {
517 $form['mass_contact_form_information'] = array(
518 '#type' => 'textarea',
519 '#title' => t('Additional information for Mass Contact form'),
520 '#default_value' => variable_get('mass_contact_form_information', t('Send e-mails using the following form.')),
521 '#description' => t('Information to show on the <a href="@form">Mass Contact page</a>.', array('@form' => url('mass_contact'))),
522 );
523
524 $form['mass_contact_character_set'] = array(
525 '#type' => 'textfield',
526 '#title' => t('Character set'),
527 '#default_value' => variable_get('mass_contact_character_set', ''),
528 '#description' => t('You may specify an alternate character set to use when sending e-mails. If left blank, the default of UTF-8 will be used. If you are unsure of what to put here, then leave it blank. Caution: setting this may not get you the results you desire. Other modules may come along and change that value after it has been set by this module.'),
529 );
530
531 $form['mass_contact_default_sender'] = array(
532 '#type' => 'fieldset',
533 '#title' => t('Default sender information'),
534 '#description' => t('If anything is specified in here, it is used in place of the "Your name" and "Your e-mail address" fileds when sending the mass e-mail. Otherwise, the sender\'s name and e-mail address will be the default values. You must fill in both values, if you want to specify a default.'),
535 );
536 $form['mass_contact_default_sender']['mass_contact_default_sender_name'] = array(
537 '#type' => 'textfield',
538 '#title' => t('Default sender name'),
539 '#default_value' => variable_get('mass_contact_default_sender_name', ''),
540 '#size' => 60,
541 '#maxlength' => 128,
542 '#description' => t('The optional user name to send e-mail as. Replaces the "Your name" value when sending mass e-mails.'),
543 );
544 $form['mass_contact_default_sender']['mass_contact_default_sender_email'] = array(
545 '#type' => 'textfield',
546 '#title' => t('Default sender e-mail address'),
547 '#default_value' => variable_get('mass_contact_default_sender_email', ''),
548 '#size' => 60,
549 '#maxlength' => 128,
550 '#description' => t('The optional user e-mail address to send e-mail as. Replaces the "Your e-mail address" value when sending mass e-mails.'),
551 );
552 $form['mass_contact_default_sender']['mass_contact_default_sender_changable'] = array(
553 '#type' => 'checkbox',
554 '#title' => t('Allow the sender to change these values.'),
555 '#default_value' => variable_get('mass_contact_default_sender_changable', 0),
556 '#description' => t('If checked, gives the sender the ability of changing the default sender and e-mail address when creating the message. If unchecked, the fields will be disabled.'),
557 );
558
559 $form['mass_contact_recipient_limit'] = array(
560 '#type' => 'textfield',
561 '#title' => t('Maximum number of recipients before splitting up the e-mail'),
562 '#size' => 4,
563 '#default_value' => variable_get('mass_contact_recipient_limit', 0),
564 '#description' => t('This is a workaround for server-side limits on the number of recipients in a single mail message. Once this limit is reached, the recipient list will be broken up and multiple copies of the message will be sent out until all recipients receive the mail. Setting this to "0" will turn off this feature.'),
565 '#required' => TRUE,
566 );
567
568 $form['mass_contact_optout_d'] = array(
569 '#type' => 'checkbox',
570 '#title' => t('Allow users to opt-out of mass e-mails.'),
571 '#default_value' => variable_get('mass_contact_optout_d', 0),
572 );
573
574 $form['mass_contact_bcc_d'] = array(
575 '#type' => 'checkbox',
576 '#title' => t('Send as BCC (hide recipients) by default.'),
577 '#default_value' => variable_get('mass_contact_bcc_d', 1),
578 );
579 $form['mass_contact_bcc_d_override'] = array(
580 '#type' => 'checkbox',
581 '#title' => t('Allow sender to override BCC setting.'),
582 '#default_value' => variable_get('mass_contact_bcc_d_override', 1),
583 );
584
585 $form['mass_contact_category_override'] = array(
586 '#type' => 'checkbox',
587 '#title' => t('Include category in subject line.'),
588 '#default_value' => variable_get('mass_contact_category_override', 1),
589 );
590
591 $form['mass_contact_supplemental_texts'] = array(
592 '#type' => 'fieldset',
593 '#title' => t('Supplemental message body texts'),
594 '#description' => t('You may specify additional text to insert before and/or after the message text of every mass e-mail that is sent.'),
595 );
596 if (module_exists('token')) {
597 $form['mass_contact_supplemental_texts']['mass_contact_message_prefix'] = array(
598 '#type' => 'textarea',
599 '#title' => t('Text to be prepended to all messages'),
600 '#default_value' => variable_get('mass_contact_message_prefix', t('[user-name] has sent you a group e-mail from [site-name].')),
601 '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed before the message text enetered in by the sender.'),
602 );
603 $form['mass_contact_supplemental_texts']['mass_contact_message_suffix'] = array(
604 '#type' => 'textarea',
605 '#title' => t('Text to be appended to all messages'),
606 '#default_value' => variable_get('mass_contact_message_suffix', t('')),
607 '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed after the message text enetered in by the sender.'),
608 );
609 $form['mass_contact_supplemental_texts']['mass_contact_replacement_tokens'] = array(
610 '#type' => 'fieldset',
611 '#title' => t('Replacement tokens'),
612 '#collapsible' => TRUE,
613 '#collapsed' => TRUE,
614 '#description' => t('You may use any of the following replacements tokens for use in the prefix and/or suffix texts above.'),
615 );
616 $form['mass_contact_supplemental_texts']['mass_contact_replacement_tokens']['token_help'] = array(
617 '#value' => theme('token_help', 'global'),
618 );
619 }
620 else {
621 $form['mass_contact_supplemental_texts']['mass_contact_message_prefix'] = array(
622 '#type' => 'textarea',
623 '#title' => t('Text to be prepended to all messages'),
624 '#default_value' => variable_get('mass_contact_message_prefix', t('You were sent a group e-mail from !site.', array('!site' => url(NULL, array('absolute' => TRUE))))),
625 '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed before the message text enetered in by the sender.'),
626 );
627 $form['mass_contact_supplemental_texts']['mass_contact_message_suffix'] = array(
628 '#type' => 'textarea',
629 '#title' => t('Text to be appended to all messages'),
630 '#default_value' => variable_get('mass_contact_message_suffix', t('')),
631 '#description' => t('The text you specify above will be added to all e-mails sent out. The text will be placed after the message text enetered in by the sender.'),
632 );
633 }
634
635 $form['mass_contact_html_d'] = array(
636 '#type' => 'checkbox',
637 '#title' => t('Send as HTML by default.'),
638 '#default_value' => variable_get('mass_contact_html_d', 1),
639 '#description' => t('This will use the default input filter as specified on the <a href="@formats_settings">Input formats settings</a> page.', array('@formats_settings' => url('admin/settings/filters'))),
640 );
641 $form['mass_contact_html_d_override'] = array(
642 '#type' => 'checkbox',
643 '#title' => t('Allow sender to override HTML setting.'),
644 '#default_value' => variable_get('mass_contact_html_d_override', 1),
645 );
646
647 $form['mass_contact_attachment_location'] = array(
648 '#type' => 'textfield',
649 '#title' => t('Attachment location'),
650 '#default_value' => variable_get('mass_contact_attachment_location', file_directory_path() .'/mass_contact_attachments'),
651 '#description' => t('If a copy of the message is saved as a node, this is the file path where to save the attachment so it can be viewed later.'),
652 );
653
654 $form['mass_contact_nodecc_d'] = array(
655 '#type' => 'checkbox',
656 '#title' => t('Save a copy as a node by default.'),
657 '#default_value' => variable_get('mass_contact_nodecc_d', 1),
658 );
659 $form['mass_contact_nodecc_d_override'] = array(
660 '#type' => 'checkbox',
661 '#title' => t('Allow sender to override node copy setting.'),
662 '#default_value' => variable_get('mass_contact_nodecc_d_override', 1),
663 );
664
665 $form['mass_contact_hourly_threshold'] = array(
666 '#type' => 'select',
667 '#title' => t('Hourly threshold'),
668 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 75, 100)),
669 '#default_value' => variable_get('mass_contact_hourly_threshold', 3),
670 '#description' => t('The maximum number of Mass Contact form submissions a user can perform per hour.'),
671 );
672
673 return system_settings_form($form);
674 } // End of mass_contact_admin_settings().
675
676
677
678 /**
679 * Validates the administration settings form.
680 *
681 * @param form
682 * An associative array containing the structure of the form.
683 * @param form_state
684 * A keyed array containing the current state of the form.
685 */
686 function mass_contact_admin_settings_validate($form, &$form_state) {
687 if (!empty($form_state['values']['mass_contact_default_sender_name'])) {
688 if (empty($form_state['values']['mass_contact_default_sender_email'])) {
689 form_set_error('mass_contact_default_sender_email', t('If you are going to specify default user settings, you must specify both a user name and a user e-mail address.'));
690 }
691 }
692
693 if (!empty($form_state['values']['mass_contact_default_sender_email'])) {
694 if (empty($form_state['values']['mass_contact_default_sender_name'])) {
695 form_set_error('mass_contact_default_sender_name', t('If you are going to specify default user settings, you must specify both a user name and a user e-mail address.'));
696 }
697 }
698 } // End of mass_contact_admin_settings_validate().
699
700
701
702 /* ********************************
703 *
704 * Functions for sending a message.
705 *
706 * *******************************/
707
708
709
710 /**
711 * The mail page
712 *
713 * @return
714 * Either an error, if flood control is active and triggered, or a
715 * rendered form.
716 */
717 function mass_contact_site_page() {
718 global $user;
719
720 if (!user_access('administer mass contact') && !flood_is_allowed('mass_contact', variable_get('mass_contact_hourly_threshold', 3))) {
721 $output = t("You cannot send more than %number messages per hour. Please try again later.", array('%number' => variable_get('mass_contact_hourly_threshold', 3)));
722 }
723 else {
724 $output = drupal_get_form('mass_contact_mail_page');
725 }
726
727 return $output;
728 } // End of mass_contact_site_page().
729
730
731
732 /**
733 * Generates the main Mass Contact mail form.
734 *
735 * @param form_state
736 * A keyed array containing the current state of the form.
737 * @return
738 * An associative array that defines the form to be built.
739 */
740 function mass_contact_mail_page($form_state) {
741 global $user;
742 $categories = array();
743 $default_category = array();
744 $default_category_name = '';
745
746 $result = db_query("SELECT cid, category, selected FROM {mass_contact} ORDER BY weight, category");
747 while ($category = db_fetch_object($result)) {
748 if (user_access('send to users in the '. $category->category .' category')) {
749 $categories[$category->cid] = $category->category;
750
751 if ($category->selected) {
752 $default_category[] = $category->cid;
753 $default_category_name = $category->category;
754 }
755 }
756 }
757
758 if (count($categories) == 1) {
759 $default_category[] = $category->cid;
760 $default_category_name = $category->category;
761 }
762
763 if (count($categories) > 0) {
764 $form['#attributes'] = array(
765 'enctype' => "multipart/form-data"
766 );
767 $form['#token'] = $user->name . $user->mail;
768 $form['contact_information'] = array(
769 '#value' => filter_xss_admin(variable_get('mass_contact_form_information', t('Send an e-mail message using the contact form below.')))
770 );
771
772 $mass_contact_default_sender_name = variable_get('mass_contact_default_sender_name', '');
773 if ($mass_contact_default_sender_name) {
774 $form['name'] = array(
775 '#type' => 'textfield',
776 '#title' => t('Your name'),
777 '#maxlength' => 255,
778 '#default_value' => $mass_contact_default_sender_name,
779 '#disabled' => !variable_get('mass_contact_default_sender_changable', 0),
780 );
781 }
782 else {
783 $form['name'] = array(
784 '#type' => 'textfield',
785 '#title' => t('Your name'),
786 '#maxlength' => 255,
787 '#default_value' => $user->uid ? $user->name : '',
788 '#required' => TRUE,
789 );
790 }
791
792 $mass_contact_default_sender_email = variable_get('mass_contact_default_sender_email', '');
793 if ($mass_contact_default_sender_email) {
794 $form['mail'] = array(
795 '#type' => 'textfield',
796 '#title' => t('Your e-mail address'),
797 '#maxlength' => 255,
798 '#default_value' => $mass_contact_default_sender_email,
799 '#disabled' => !variable_get('mass_contact_default_sender_changable', 0),
800 );
801 }
802 else {
803 $form['mail'] = array(
804 '#type' => 'textfield',
805 '#title' => t('Your e-mail address'),
806 '#maxlength' => 255,
807 '#default_value' => $user->uid ? $user->mail : '',
808 '#required' => TRUE,
809 );
810 }
811
812 if ((count($categories) > 1) || !isset($default_category)) {
813 // Display a choice when one is needed.
814 $form['cid'] = array(
815 '#type' => 'select',
816 '#title' => t('Category'),
817 '#default_value' => $default_category,
818 '#options' => $categories,
819 '#required' => TRUE,
820 '#multiple' => TRUE,
821 );
822 }
823 else {
824 // Otherwise, just use the default category.
825 $form['cid'] = array(
826 '#type' => 'value',
827 '#value' => $default_category, // This must be an array, otherwise the code breaks upon submit.
828 );
829 $form['cid-info'] = array(
830 '#type' => 'markup',
831 '#value' => '<p>Sending to all users subscribed to the '. $default_category_name .' category.</p>',
832 );
833 }
834
835 if (variable_get('mass_contact_optout_d', 0) == 1) {
836 // Allow to override or respect opt-outs if admin, otherwise use default.
837 if (user_access('administer mass contact')) {
838 $form['optout'] = array(
839 '#type' => 'checkbox',
840 '#title' => t('Respect user opt-outs.'),
841 '#default_value' => 1,
842 );
843 }
844 else {
845 $form['optout'] = array(
846 '#type' => 'hidden',
847 '#default_value' => 1,
848 );
849 }
850 }
851
852 // Check if the user can override the BCC setting.
853 if (variable_get('mass_contact_bcc_d_override', 1)) {
854 $form['bcc'] = array(
855 '#type' => 'checkbox',
856 '#title' => t('Send as BCC (hide recipients).'),
857 '#default_value' => variable_get('mass_contact_bcc_d', 1),
858 );
859 }
860 // If not, then just display the BCC info.
861 else {
862 $form['bcc'] = array(
863 '#type' => 'value',
864 '#value' => variable_get('mass_contact_bcc_d', 1),
865 );
866 $form['bcc-info'] = array(
867 '#type' => 'markup',
868 '#value' => '<p>'. (variable_get('mass_contact_bcc_d', 1) ? t('Recipients will be hidden.') : t('Recipients will NOT be hidden.')) .'</p>',
869 );
870 }
871
872 $form['subject'] = array(
873 '#type' => 'textfield',
874 '#title' => t('Subject'),
875 '#maxlength' => 255,
876 '#required' => TRUE,
877 );
878
879 $form['message'] = array(
880 '#type' => 'textarea',
881 '#title' => t('Message'),
882 '#required' => TRUE,
883 );
884
885 if (user_access('send mass contact attachments')) {
886 $form['attachment'] = array(
887 '#type' => 'file',
888 '#title' => t('Attachment'),
889 '#size' => 40,
890 );
891 }
892
893 // Check if the user can override the HTML setting.
894 if (variable_get('mass_contact_html_d_override', 1)) {
895 $form['html'] = array(
896 '#type' => 'checkbox',
897 '#title' => t('Send as HTML.'),
898 '#default_value' => variable_get('mass_contact_html_d', 1),
899 '#description' => t('This will use the settings for the default input filter. More information about what is available is on the <a href="@formats_settings">Input formats</a> page.', array('@formats_settings' => url('filter/tips'))),
900 );
901 }
902 // If not, then just display the HTML info.
903 else {
904 $form['html'] = array(
905 '#type' => 'value',
906 '#value' => variable_get('mass_contact_html_d', 1),
907 );
908 $form['html-info'] = array(
909 '#type' => 'markup',
910 '#value' => '<p>'. (variable_get('mass_contact_html_d', 1) ? t('The message will be sent as HTML.') : t('The message will be sent as plain text.')) .'</p>',
911 );
912 }
913
914 // We do not allow anonymous users to send themselves a copy because it
915 // can be abused to spam people.
916 if ($user->uid) {
917 $form['copy'] = array(
918 '#type' => 'checkbox',
919 '#title' => t('Send yourself a copy.'),
920 '#weight' => $i,
921 );
922 }
923
924 if (user_access('choose whether to archive mass contact messages')) {
925 // Check if the user can override the node copy setting.
926 if (variable_get('mass_contact_nodecc_d_override', 1)) {
927 $form['nodecc'] = array(
928 '#type' => 'checkbox',
929 '#title' => t('Save a copy as a node.'),
930 '#default_value' => variable_get('mass_contact_nodecc_d', 1),
931 );
932 }
933 // If not, then do it or not based on the administrative setting.
934 else {
935 $form['nodecc'] = array(
936 '#type' => 'hidden',
937 '#default_value' => variable_get('mass_contact_nodecc_d', 1),
938 );
939 }
940 }
941 // If not, then do it or not based on the administrative setting.
942 else {
943 $form['nodecc'] = array(
944 '#type' => 'hidden',
945 '#default_value' => variable_get('mass_contact_nodecc_d', 1),
946 );
947 }
948
949 /*
950 // Place holder for future use.
951 $form['preview'] = array(
952 '#type' => 'button',
953 '#value' => t('Preview')
954 );
955 */
956 $form['submit'] = array(
957 '#type' => 'submit',
958 '#value' => t('Send e-mail'),
959 );
960 }
961 else {
962 $form['error'] = array(
963 '#value' => '<p><b>'. t('Either you have not created any categories, or you are not allowed to send to any of the existing categories.') .'<br /><br />'. t('Either create at least one category of users to send to, or contact your system administer for access to the existing categories.') .'</b>',
964 );
965 }
966
967 if (user_access('administer mass contact')) {
968 $form['tasklist'] = array(
969 '#type' => 'fieldset',
970 '#title' => t('Related tasks'),
971 '#collapsible' => TRUE,
972 '#collapsed' => FALSE,
973 '#prefix' => '<p>',
974 );
975 $form['tasklist']['list'] = array(
976 '#value' => '<p><ol>'.
977 '<li>' . l('Set Permissions', 'admin/user/permissions', array('fragment' => 'module-mass_contact')) .'</li>'.
978 '<li>' . l('List current categories', 'admin/build/mass_contact') .'</li>'.
979 '<li>' . l('Add new category', 'admin/build/mass_contact/add') .'</li>'.
980 '<li>' . l('Configure the module', 'admin/build/mass_contact/settings') .'</li>'.
981 '<li>' . l('Help', 'admin/help/mass_contact') .'</li></ol>',
982 );
983 }
984
985 return $form;
986 } // End of mass_contact_mail_page().
987
988
989
990 /**
991 * Validates the main Mass Contact mail form.
992 *
993 * @param form
994 * An associative array containing the structure of the form.
995 * @param form_state
996 * A keyed array containing the current state of the form.
997 */
998 function mass_contact_mail_page_validate($form, &$form_state) {
999 if (!$form_state['values']['cid']) {
1000 form_set_error('category', t('You must select a valid category.'));
1001 }
1002 if (!valid_email_address($form_state['values']['mail'])) {
1003 form_set_error('mass_contact', t('You must enter a valid e-mail address.'));
1004 }
1005 } // End of mass_contact_mail_page_validate().
1006
1007
1008
1009 /**
1010 * Processes the main Mass Contact mail form.
1011 *
1012 * @param form
1013 * An associative array containing the structure of the form.
1014 * @param form_state
1015 * A keyed array containing the current state of the form.
1016 */
1017 function mass_contact_mail_page_submit($form, &$form_state) {
1018 global $user;
1019
1020 $bcc = $form_state['values']['bcc'];
1021 $nodecc = $form_state['values']['nodecc'];
1022 $send_error = 0;
1023 // E-mail address of the sender: as the form field is a text field,
1024 // all instances of \r and \n have been automatically stripped from it.
1025 $from = $form_state['values']['mail'];
1026 $uid = '';
1027 $ctype = '';
1028 $message_attachment = array();
1029 $params = array();
1030 $character_set = variable_get('mass_contact_character_set', 'UTF-8');
1031
1032 if (!$character_set) {
1033 $character_set = 'UTF-8';
1034 }
1035
1036 // Create the headers based on presence or absence of an attachment.
1037 if ($_FILES['files']['size']['attachment'] > 0) {
1038 $uid = md5(uniqid(time()));
1039 $params['headers']['Content-Type'] = 'multipart/mixed; boundary="'. $uid .'"';
1040
1041 if ($form_state['values']['html'] == 1) {
1042 $params['body'][] = "\n--". $uid ."\nContent-Type: text/html; charset=". $character_set ."; format=flowed\n\n";
1043 }
1044 else {
1045 $params['body'][] = "\n--". $uid ."\nContent-Type: text/plain; charset=". $character_set ."; format=flowed\n\n";
1046 }
1047 }
1048 elseif ($form_state['values']['html'] == 1) {
1049 $params['headers']['Content-Type'] = 'text/html; charset='. $character_set .'; format=flowed';
1050 }
1051 elseif ($character_set) {
1052 $params['headers']['Content-Type'] = 'text/plain; charset='. $character_set .'; format=flowed';
1053 }
1054
1055
1056 // Compose the body:
1057 // Start with the message prefix.
1058 if (module_exists('token')) {
1059 $params['body'][] = token_replace(variable_get('mass_contact_message_prefix', ''));
1060 $node_message[] = token_replace(variable_get('mass_contact_message_prefix', ''));
1061 }
1062 else {
1063 $params['body'][] = variable_get('mass_contact_message_prefix', '');
1064 $node_message[] = variable_get('mass_contact_message_prefix', '');
1065 }
1066
1067 if ($form_state['values']['html'] == 1) {
1068 // Add a spacer for HTML formatted messages.
1069 $params['body'][] = "<p>";
1070 $node_message[] = "<p>";
1071
1072 // Add in the actual message.
1073 $params['body'][] = check_markup(wordwrap($form_state['values']['message']));
1074 $node_message[] = check_markup(wordwrap($form_state['values']['message']));
1075
1076 // Add a spacer for HTML formatted messages.
1077 $params['body'][] = "<p>";
1078 $node_message[] = "<p>";
1079 }
1080 else {
1081 // Add in the actual message.
1082 $params['body'][] = check_plain(wordwrap($form_state['values']['message']));
1083 $node_message[] = check_plain(wordwrap($form_state['values']['message']));
1084 }
1085
1086 // End with the message suffix.
1087 if (module_exists('token')) {
1088 $params['body'][] = token_replace(variable_get('mass_contact_message_suffix', ''));
1089 $node_message[] = token_replace(variable_get('mass_contact_message_suffix', ''));
1090 }
1091 else {
1092 $params['body'][] = variable_get('mass_contact_message_suffix', '');
1093 $node_message[] = variable_get('mass_contact_message_suffix', '');
1094 }
1095
1096 // Add attachment.
1097 if ($_FILES['files']['size']['attachment'] > 0) {
1098 /*
1099 if (module_exists('mimemail') && variable_get('mimemail_alter', 0) == 1) {
1100 $message_attachment = array(
1101 array(
1102 'filepath' => $_FILES['files']['tmp_name']['attachment'],
1103 'filename' => $_FILES['files']['name']['attachment'],
1104 'filemime' => $_FILES['files']['type']['attachment'],
1105 )
1106 );
1107 }
1108 else {
1109 */
1110 $message_attachment = '--'. $uid ."\n";
1111 $message_attachment .= "Content-Type: ". $_FILES['files']['type']['attachment'] ."; name=\"". basename($_FILES['files']['name']['attachment']) ."\"\n";
1112 $message_attachment .= "Content-Transfer-Encoding: base64\n";
1113 $message_attachment .= "Content-Disposition: attachment; filename=\"". basename($_FILES['files']['name']['attachment']) ."\"\n\n";
1114 $message_attachment .= chunk_split(base64_encode(file_get_contents($_FILES['files']['tmp_name']['attachment'])));
1115 $message_attachment .= "\n\n--". $uid ."--\n\n";
1116
1117 $params['body'][] = $message_attachment;
1118 // }
1119 }
1120
1121
1122 ///////////////////////////////////////////////////////////////////////////
1123 //
1124 // @TODO: The whole rest of this function needs to be re-thought out and
1125 // refactored, possibly separating some of it out into other
1126 // functions.
1127 //
1128 ///////////////////////////////////////////////////////////////////////////
1129
1130 /*
1131
1132 Task order:
1133 Get the list of categories
1134 Create the list of recipients
1135 Compose the e-mail message, starting w/the header
1136
1137 */
1138
1139 // Load the category information.
1140 $cids = array();
1141 foreach ($form_state['values']['cid'] as $cid) {
1142 $cids[] = $cid;
1143 }
1144
1145 $result = db_query("SELECT * FROM {mass_contact} WHERE cid IN(". db_placeholders($cids) .