Mailinglist
 All Data Structures Files Functions Variables Pages
mailinglist.module
Go to the documentation of this file.
1 <?php
34 /******************************************************************************/
35 /* Drupal hooks */
36 /******************************************************************************/
37 
42  $lists = mailinglist_list_load_all(false);
44 
45  $permissions = array(
46  'administer mailinglist' => array(
47  'title' => t('Administer Mailinglist mailboxes'),
48  ),
49  );
50  foreach ($lists as $index => $list) {
51  $permissions['mailinglist ' . $index] = array(
52  'title' => t('Access ' . $list->admin_title),
53  );
54  foreach ($opers as $oindex => $oper) {
55  $permissions['mailinglist ' . $index . ' ' . $oindex] = array(
56  'title' => t($list->admin_title . ' ' . $oper->plugin['name']),
57  );
58  }
59  }
60  return $permissions;
61 }
62 
68 function mailinglist_help($path, $arg) {
70  switch ($path) {
71  case 'admin/help#mailinglist':
72  $help = file_get_contents( dirname(__FILE__) . "/INSTALL.txt");
73  return _filter_autop($help);
74  break;
75  case 'admin/config/system/mailinglist/list/add':
76  return t('Add help here');
77  }
78 }
79 
85 function mailinglist_menu() {
86  $base = variable_get('mailinglist_base', 'mailinglist');
87  $items = array(
88  // User Pages
89  $base => array(
90  'title' => 'Mailing Lists',
91  'description' => 'Entry page for Mailinglist Module',
92  'type' => MENU_CALLBACK,
93  'page callback' => '_mailinglist_pagecallback',
94  'page arguments' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
95  'access arguments' => array('access content'),
96  'file' => 'mailinglist.pagecallback.inc',
97  ),
98  $base . '/%mailinglist_list' => array(
99  'title' => 'MailingList Page',
100  'description' => 'Entry page for Mailinglist Module',
101  'type' => MENU_CALLBACK,
102  'page callback' => '_mailinglist_list_pagecallback',
103  'page arguments' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
104  'access arguments' => array('access content'),
105  'file' => 'mailinglist.pagecallback.inc',
106  ),
107  $base . '/%mailinglist_list/%mailinglist_operation' => array(
108  'title' => 'Mailing Lists Operation',
109  'description' => 'Manage Mailing Operation Page',
110  'type' => MENU_NORMAL_ITEM,
111  'page callback' => 'drupal_get_form',
112  'page arguments' => array('mailinglist_operation_form', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
113  'access arguments' => array('access content'),
114  'file' => 'mailinglist.pagecallback.inc',
115  ),
116  // Admin Pages
117  'admin/config/system/mailinglist' => array(
118  'title' => 'Mailing Lists Configuration',
119  'description' => 'Manage Mailing List Interface',
120  'type' => MENU_NORMAL_ITEM,
121  'page callback' => 'drupal_get_form',
122  'page arguments' => array('_mailinglist_config_form'),
123  'access arguments' => array('administer mailinglist'),
124  'file' => 'mailinglist.admin.inc',
125  ),
126  'admin/config/system/mailinglist/config' => array(
127  'title' => 'Config',
128  'type' => MENU_DEFAULT_LOCAL_TASK,
129  'page callback' => 'drupal_get_form',
130  'page arguments' => array('_mailinglist_config_form'),
131  'access arguments' => array('administer mailinglist'),
132  'file' => 'mailinglist.admin.inc',
133  ),
134  );
135  return $items;
136 }
137 
143  $queue = array(
144  'mailinglist_message' => array(
145  'worker callback' => 'mailinglist_message_callback',
146  'time' => '20',
147  ),
148  );
149  return $queue;
150 }
151 
152 
156 function mailinglist_cron() {
157 
158  $boxes = mailinglist_mailbox_load_all(false);
160  foreach ($boxes as $index => $box) {
161 // if (isset($list1->operations['members']) && $list1->operations['members']) {
162 // mailinglist_members_scan($list1);
163 // }
164  }
165 }
166 
167 /*
168 function hook_node_info() {
169 return array(
170  machine_name_for_node_type => array(
171  'name' => 'Human Readable Name',
172  'base' => 'base string to build callback function name (mailinglist_nodetype)',
173  'description' => 'Brief Description',
174  'help' => '(opt) Help displayed when creating nodes',
175  'has_title' => TRUE, //(or FALSE) does type have a "title" FIELD.
176  'title_lable' => 'Label for Title Field',
177  'locked' => TRUE, //(or FALSE), can machine name be changed in admin interface
178  ),
179  ...
180 );
181 
182 // displayed to create/edit a node, return the form
183 function hook_form($node, &$form_state) {
184 }
185 
186 might just be:
187  return node_content_form($node, $form_state);
188 
189 
190 if node as a non-empty nid member, then node will update that nid.
191 
192 function hook_insert($node){
193  called by node_save() after node inserted into node table and before
194 }
195 
196 function hook_update($node) {
197  like above but for an update
198 }
199 
200 function hook_delete($node) {
201  delete specified node
202 }
203 
204 function hook_load($nodes) {
205 $nodes is an array, fill in the elements with the node data based on the keys.
206 
207 Something like:
208  $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN (:nids)', array(':nids' => array_keys($nodes)));
209  foreach ($result as $record) {
210  $nodes[$record->nid]->foo = $record->foo;
211  }
212 }
213 */
214 
215 /******************************************************************************/
216 /* mbox file scanning routines */
217 /******************************************************************************/
218 
223  // Get path to store files for processing
224  $path = variable_get('file_private_path');
225  // If we don/t have a private path, get a public one, with defualts
226  if (empty($path)) {
227  $path = variable_get('file_public_path', conf_path() . '/files');
228  }
229  // Update to make absolute, and our sub directory
230  $path = DRUPAL_ROOT . '/' . $path . '/mailinglist';
231  $flag = file_prepare_directory($path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
232  return $path;
233 }
234 
239 function _mailinglist_base_filename($path) {
240  $base = _mailinglist_file_path() . '/';
241  return str_replace($base, '', $path);
242 }
243 
249 
250  $boxes = mailinglist_mailbox_load_all(false);
251  foreach ($boxes as $index => $box) {
252 // dpm($box, $index);
253  }
254 }
255 
266  $queue = DrupalQueue::get('mailinglist_message');
267  $path = _mailinglist_file_path();
268  // Get the mailbox we are currently processing
269  $file = variable_get('mailinglist_mailbox_current', FALSE);
270 
271  if ($file == FALSE) {
272  if($queue->numberOfItems() > 100) {
273  return; // If behind, don't start up a new file
274  }
275  $files = file_scan_directory($path, '/.*/');
276  ksort($files);
277  if (empty($files)) {
278  dpm('Nothing', 'mailinglist_maildir_scan');
279  return; // Nothing to do
280  }
281  $file = array_keys($files);
282  $file = $file[0];
283 
284  $handle = fopen($file, 'r');
285  fseek($handle, 0, SEEK_END);
286  $end = ftell($handle);
287 
288  $local = substr($file, strlen($path)+1);
289  $pos = strpos($local, '/');
290  if ($pos > 0) {
291  $listname = substr($local, 0, $pos);
292  }
293  else {
294  $listname = FALSE;
295  }
296  watchdog('Mailinglist', 'Starting @file (@msg) @list',
297  array('@msg' => $end,
298  '@file' => _mailinglist_base_filename($file),
299  '@list' => $listname),
300  WATCHDOG_NOTICE);
301  dpm($listname, 'list');
302  $offset = 0;
303  variable_set('mailinglist_mailbox_current', $file);
304  variable_set('mailinglist_mailbox_current_offset', $offset);
305  variable_set('mailinglist_mailbox_current_list', $listname);
306  variable_set('mailinglist_mailbox_current_max', $end);
307  }
308  else {
309  if($queue->numberOfItems() > 1000) {
310  return; // If far behind, don't queue up more from file
311  }
312  // Continuing with a file, get rest of details.
313  $offset = variable_get('mailinglist_mailbox_current_offset');
314  $listname = variable_get('mailinglist_mailbox_current_list');
315  $msgcnt = variable_get('mailinglist_mailbox_current_max');
316  }
317 
318  if ($listname) {
319  $list = mailinglist_list_load($listname);
320  }
321  else {
322  $list = FALSE;
323  }
324  if ($list == FALSE) {
325  $lists = mailinglist_list_load_all(FALSE);
326  }
327 
328  $offset = _mailinglist_mailbox_process($list, $file, $offset);
329 
330  if ($offset === FALSE) {
331  variable_set('mailinglist_mailbox_current', FALSE);
332  variable_set('mailinglist_mailbox_current_offset', 0);
333  }
334  else {
335  dpm($offset);
336  variable_set('mailinglist_mailbox_current_offset', $offset);
337  }
338 }
339 
352 function _mailinglist_mailbox_process($list, $file, $offset) {
353  $time = time();
354  $queue = DrupalQueue::get('mailinglist_message');
355  $handle = fopen($file, 'r');
356  if (!$handle) {
357  // File not found
358  watchdog('Mailinglist', 'File not found @file',
359  array('@file' => _mailinglist_base_filename($file)),
360  WATCHDOG_NOTICE);
361  dpm($file, 'File Not found');
362  fclose($handle);
363  return FALSE;
364  }
365  fseek($handle, $offset);
366 
367  $fromline = fgets($handle);
368  $cnt = 0;
369  while( time() < $time+20 && $cnt < 1000) {
370  $cnt = $cnt + 1;
371  $msg = "";
372  while (1) {
373  // Remember where we were if we are now done.
374  $offset = ftell($handle);
375  $line = fgets($handle);
376  if ($line === FALSE || substr($line, 0, 5) == 'From ') {
377  $fromline = $line;
378  break; // message done
379  }
381  $msg .= $line;
382  }
383  if ($msg == "" && $fromline == FALSE) {
384  watchdog('Mailinglist', 'End of File @file',
385  array('@file' => _mailinglist_base_filename($file)),
386  WATCHDOG_NOTICE);
387  dpm('End of File: ' . $file);
388  unlink($file);
389  return FALSE;
390  }
391  $msg = new MailinglistMessage($msg);
392  $headers = $msg->headers();
393  if(!isset($headers['From']) || !isset($headers['Date']) || !isset($headers['Subject'])){
394 
395  watchdog('Mailinglist', 'Bad message @file @offset @from MSG: @msg' ,
396  array('@file' => _mailinglist_base_filename($file),
397  '@offset' => $offset,
398  '@from' => $fromline,
399  '@msg' => check_plain(print_r($msg, TRUE)),
400  ),
401  WATCHDOG_ERROR);
402  continue;
403  }
404  $from = $msg->header('From');
405  if (is_array($from)) {
406  $from = $from[0];
407  }
408  if (strpos($from, '@') == FALSE) {
409  // obfuscated from line from archives
410  $from = str_replace(' at ', '@', $from);
411  $msg->setHeader('From', $from);
412  }
414 
415  if ($list) {
416  // List Specific, give to that list, assume it is to be archived
417  $msg->setHeader('XX-List', $list->admin_name);
418  $msg->setHeader('XX-Archive', '1');
419  $msg->setHeader('XX-Status', 0);
420  }
421  $queue->createItem($msg);
422  }
423  fclose($handle);
424  return $offset;
425 }
426 
427 /******************************************************************************/
428 /* Message Pumping */
429 /******************************************************************************/
430 
437  $listname = $msg->header('XX-List');
438 
439  if ($listname) {
440  $list = mailinglist_list_load($listname);
441  }
442  else {
443  $list = FALSE;
444  }
445  if($list) {
446  $list->processMessage($msg);
447  } else {
448  // No valid list specified, check all the lists.
449  $lists = mailinglist_list_load_all(FALSE);
450  foreach ($lists as $list1) {
451  $flag = $list1->checkMessage($msg);
452  }
453  }
454 }
455 
456 /******************************************************************************/
457 /* General Utility Functions */
458 /******************************************************************************/
459 
466  $seed = mt_rand(0, 255);
467  $str = chr($seed);
468  for ($i=0; $i < strlen($pass); $i++) {
469  $seed = ($seed + ord($pass[$i])) % 256;
470  $str .= chr($seed);
471  }
472  $encode = base64_encode($str);
473  return $encode;
474 }
475 
482  if (empty($code)) return $code;
483  $decode = base64_decode($code);
484  $seed = ord($decode[0]);
485  $pass = '';
486  for ($i=1; $i < strlen($decode); $i++) {
487  $ch = ord($decode[$i]);
488  $seed = $ch - $seed;
489  if ($seed < 0) $seed += 256;
490  $pass .= chr($seed);
491  $seed = $ch;
492  }
493  return $pass;
494 }
495 
523 function mailinglist_array_merge_recursive_distinct(array &$array1, array &$array2) {
524  $merged = $array1;
525 
526  foreach ( $array2 as $key => &$value ) {
527  if ( is_array ( $value ) && isset ( $merged [$key] ) && is_array ( $merged [$key] ) ) {
528  $merged [$key] = mailinglist_array_merge_recursive_distinct($merged [$key], $value);
529  }
530  else {
531  $merged [$key] = $value;
532  }
533  }
534 
535  return $merged;
536 }
537 
538 /******************************************************************************/
539 /* DateTime field support */
540 /******************************************************************************/
541 
549  if (!is_array($desc)) {
550  $desc = array('description' => 'desc');
551  }
552 
553  $desc['type'] = 'char';
554  $desc['length'] = 19;
555  return $desc;
556 }
557 
562  $value = gmdate('Y-m-d H:i:s', $ts);
563 // dpm($value . " ... " . date_iso8601($ts)); date_iso uses local timezone
564  return $value;
565 }
566 
570 function _mailinglist_datetime_ts($time) {
571  return strtotime($time . " UTC");
572 }
576 function mailinglist_email_name($email, $name, $count = 0) {
577  $email = strtolower($email);
578  $sql = 'SELECT name_key from {mailinglist_names}
579  WHERE email = :email AND name = :name';
580  $result = db_query($sql, array(':email' => $email, ':name' => $name));
581  $result = $result -> fetchAssoc();
582  if (!$result) {
583  // New Combo
584  $fields = array('email' => $email, 'name' => $name);
585  dpm($fields, 'New Combo');
586  return (int) db_insert('mailinglist_names') -> fields($fields) -> execute();
587  }
588  else {
589  // Existing Combo
590  return (int) $result['name_key'];
591  }
592 }
593 
603 function mailinglist_init() {
604  if (strstr(request_uri(), 'system/ajax') && $_POST['form_id'] == 'ctools_export_ui_edit_item_form') {
605  ctools_include('export');
606  }
607 }
608 
620 function mailinglist_ctools_plugin_directory($owner, $plugin_type) {
621  return 'plugins/' . $owner . '/' . $plugin_type;
622 }
623 
628  return array(
629  'list' => array(), // List Personality Modules
630  'operation' => array(), // Extension Modules
631  'retrieve' => array(), // Data Retrieval Modules
632  );
633 }
634 
652 function mailinglist_plugin_load_class($module, $type, $plugin, $class_name='handler', $args = NULL) {
653  ctools_include('plugins');
654  $class = ctools_plugin_load_class($module, $type, $plugin, $class_name);
655  if ($class) {
656  return new $class($args);
657  }
658 }
659 
669 function mailinglist_get_plugins($module, $type) {
670  ctools_include('plugins');
671  $plugins = ctools_get_plugins($module, $type);
672  $result = array();
673  $weights = array();
674  foreach ($plugins as $key => $info) {
675  if (!empty($info['hidden'])) {
676  continue;
677  }
678  if (!isset($info['weight'])) {
679  $info['weight'] = 10;
680  }
681  $weights[] = $info['weight'];
682  $result[$key] = $info;
683  }
684  array_multisort($weights, $result);
685  return $result;
686 }
687 
701 function _mailinglist_build_options($source, $key_name = 'name') {
702  $options = array();
703  foreach ($source as $key => $value) {
704  $options[$key] = is_object($value) ? $value->$key_name : $value[$key_name];
705  }
706  return $options;
707 }
708 
736 function _mailinglist_object_factory($schema, $data) {
737  ctools_include('plugins');
738  $type = FALSE;
739  if (isset($data->object_type)) {
740  $object_type = $data->object_type;
741  $owner = $schema['export']['api']['owner'];
742  $api = $schema['export']['api']['api'];
743  $class_name = ctools_plugin_load_class($owner, $api, $object_type, 'handler');
744  if (!class_exists($class_name)) {
745  $class_name = FALSE;
746  $class_name = $schema['fields']['object_type']['default'];
747  }
748  }
749  $object = _ctools_export_unpack_object($schema, $data, $class_name);
750  return $object;
751 }
752 
759 /********* mailbox *********/
760 
769 function mailinglist_mailbox_load($mbox) {
770  ctools_include('export');
771  $retrieve = ctools_export_crud_load('mailinglist_retrieve', $mbox);
772  return $retrieve;
773 }
774 
783 function mailinglist_mailbox_load_all($show_disabled = TRUE) {
784  ctools_include('export');
785  $mboxes = ctools_export_crud_load_all('mailinglist_retrieve');
786  foreach ($mboxes as $email => $mbox) {
787  if (isset($listdef->disabled) && $mbox->disabled && !$show_disabled) {
788  unset($mboxes[$email]);
789  }
790  }
791  return $mboxes;
792 }
793 
797 function _mailinglist_mailbox_test($form, &$form_state) {
798  $mailbox = (object)$form_state['values'];
799  return _mailinglist_mailbox_test_output($mailbox);
800 }
801 
806  $output = '<div id="mailinglist_test_results" class="form-wrapper">';
807  // Call the test function.
808  if (isset($mailbox->settings['object_type'])) {
809  $class = mailinglist_plugin_load_class('mailinglist', 'retrieve', $mailbox->settings['object_type'], 'handler');
810  if ($class) {
811  $ret = $class->test($mailbox);
812  foreach ($ret as $message) {
813  $output .= '<div class="messages ' . $message['severity'] . '">' . $message['message'] . '</div>';
814  }
815  }
816  }
817  $output .= "</div>";
818  return $output;
819 }
820 
821 /********* list *********/
822 
832 function mailinglist_list_load($list) {
833  ctools_include('export');
834  $obj = ctools_export_crud_load('mailinglist_list', $list);
835  return $obj;
836 }
837 
848 function mailinglist_list_load_all($show_disabled = TRUE) {
849  ctools_include('export');
850  $lists = ctools_export_crud_load_all('mailinglist_list');
851  foreach ($lists as $list => $listdef) {
852  if (isset($listdef->disabled) && $listdef->disabled && !$show_disabled) {
853  unset($lists[$list]);
854  }
855  }
856  return $lists;
857 }
858 
869 function mailinglist_operation_load($oper) {
870  ctools_include('plugins');
871  require_once(drupal_get_path('module', 'mailinglist') . '/plugins/mailinglist/operation/MailinglistOperation.class.php');
872  $plugin = ctools_get_plugins('mailinglist', 'operation', $oper);
873  $plugin['key'] = $oper;
874  $class = ctools_plugin_get_class($plugin, 'handler');
875  if (class_exists($class)) {
876  $obj = new $class;
877  $obj->plugin = $plugin;
878  }
879  else {
880  $obj = NULL;
881  }
882  return $obj;
883 }
884 
891  $opers = mailinglist_get_plugins('mailinglist', 'operation');
892  $ret = array();
893  foreach ($opers as $key => $plugin) {
894  $ret[$key] = mailinglist_operation_load($key);
895  }
896  return $ret;
897 }
898 
_mailinglist_mailbox_scan()
Process the configured mailing boxes.
mailinglist_help($path, $arg)
Implements hook_help().
_mailinglist_encode_password($pass)
_mailinglist_encode_password
mailinglist_array_merge_recursive_distinct(array &$array1, array &$array2)
array_merge_recursive does indeed merge arrays, but it converts values with duplicate keys to arrays ...
mailinglist_ctools_plugin_type()
Implements hook_ctools_plugin_type().
Class defining the contents of an e-mail message.
mailinglist_cron_queue_info()
Implements hook_cron_queue_info().
_mailinglist_file_path()
_mailinglist_file_path() gets the file path that we will use to place files in
_mailinglist_mailbox_test_output($mailbox)
_mailinglist_mailbox_test_output()
mailinglist_mailbox_load_all($show_disabled=TRUE)
Load all mailinglists.
_mailinglist_build_options($source, $key_name= 'name')
Builds a Select control array from a menu form an array from a ctools_get_plugin. ...
mailinglist_list_load($list)
Load a list definition.
$plugin
Definition: archive.inc:7
mailinglist_menu()
Implements hook_menu().
mailinglist_operation_load($oper)
@ name CTools Operation/******** operation
_mailinglist_datetime_schema($desc)
Return the schema for a 'datetime' field.
_mailinglist_decode_password($code)
_mailinglist_decode_password
mailinglist_get_plugins($module, $type)
Wrapper to load plugins.
_mailinglist_mailbox_test($form, &$form_state)
_mailinglist_mailbox_test
mailinglist_operation_load_all()
mailinglist_operation_load_all()
mailinglist_cron()
Implements hook_cron().
mailinglist_email_name($email, $name, $count=0)
Lookup Email <-> Name combination.
mailinglist_permission()
Implements hook_permission().
mailinglist_plugin_load_class($module, $type, $plugin, $class_name='handler', $args=NULL)
Wrapper to load any class type.
mailinglist_init()
CTOOLS Hooks
_mailinglist_object_factory($schema, $data)
Builds an type variable object from a database table entry.
mailinglist_message_callback($msg)
Message Queue Callback function.
_mailinglist_maildir_scan()
_mailinglist_mailbox_scan()
mailinglist_mailbox_load($mbox)
CTools Export UI
mailinglist_ctools_plugin_directory($owner, $plugin_type)
Implements hook_ctools_plugin_directory().
mailinglist_list_load_all($show_disabled=TRUE)
Load all mailinglists.
_mailinglist_datetime_format($ts)
Convert a 'timestamp to a 'datetime'.
_mailinglist_base_filename($path)
_mailinglist_base_filename().
_mailinglist_mailbox_process($list, $file, $offset)
_mailinglist_mailbox_process().
_mailinglist_datetime_ts($time)
Convert a 'datetime' field into a timestamp.