You are here

sms_receive.module in SMS Framework 5

File

modules/sms_receive/sms_receive.module
View source
<?php

function sms_receive_menu() {
  $items[] = array(
    'path' => 'admin/smsframework/receive',
    'title' => t('Receive'),
    'description' => t('Setting for the SMS receive module.'),
    'access' => user_access('administer smsframework'),
    'callback' => 'drupal_get_form',
    'callback arguments' => array(
      'sms_receive_admin_form',
    ),
  );
  $items[] = array(
    'path' => variable_get('sms_receive_path', 'sms/in'),
    'title' => t('SMS Receive'),
    'access' => user_access('receive sms message'),
    'callback' => 'sms_receive_receive',
    'type' => MENU_CALLBACK,
  );
  return $items;
}
function sms_receive_admin_form() {
  $types = node_get_types();
  $node_types = array();
  foreach ($types as $type) {
    $node_types[$type->type] = $type->name;
  }
  $form['sms_receive_path'] = array(
    '#type' => 'textfield',
    '#title' => t('SMS Receive Path'),
    '#description' => t('Set the path for the callback URL'),
    '#default_value' => variable_get('sms_receive_path', 'sms/in'),
  );
  $form['sms_receive_content_type'] = array(
    '#type' => 'select',
    '#title' => 'Message content type',
    '#default_value' => variable_get('sms_receive_content_type', 'page'),
    '#options' => $node_types,
    '#description' => t('Set the content type that the message is mapped to.'),
  );

  // This should be reworked to be much more configurable... multiple fields assigned either way
  $node_fields = sms_receive_type_fields(variable_get('sms_receive_content_type', 'page'));
  $sms_fields = sms_receive_sms_fields();
  if (!empty($sms_fields)) {
    foreach ($sms_fields as $sms_field) {
      $form['sms_receive_fields']['sms_receive_field_' . $sms_field] = array(
        '#type' => 'select',
        '#title' => t("Map '%field' to this text field", array(
          '%field' => $sms_field,
        )),
        '#default_value' => variable_get('sms_receive_field_' . $sms_field, ''),
        '#options' => $node_fields,
      );
    }
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}
function sms_receive_admin_form_submit($form_id, $form_values) {
  if ($form_values['sms_receive_path']) {

    // TODO: validation to check if path was actually set using sms_receive_set_callback
    global $base_url;
    sms_receive_set_callback($base_url . '/' . $form_values['sms_receive_path']);
    variable_set('sms_receive_path', $form_values['sms_receive_path']);
  }
  if ($form_values['sms_receive_content_type']) {
    variable_set('sms_receive_content_type', $form_values['sms_receive_content_type']);
  }
  $sms_fields = sms_receive_sms_fields();
  foreach ($sms_fields as $sms_field) {
    variable_set('sms_receive_field_' . $sms_field, $form_values['sms_receive_field_' . $sms_field]);
  }
}
function sms_receive_get_callback($extra = array()) {
  $gateway = sms_gateways('gateway', variable_get('sms_default_gateway', 0));
  if (function_exists($gateway['get_callback'])) {
    return $gateway['get_callback']();
  }
  else {
    drupal_set_message('Invalid gateway callback.');
  }
}
function sms_receive_set_callback($url, $extra = array()) {
  $gateway = sms_gateways('gateway', variable_get('sms_default_gateway', 0));
  if (function_exists($gateway['set_callback'])) {
    return $gateway['set_callback']($url);
  }
  else {
    drupal_set_message('Invalid gateway callback.');
  }
}

/**
 * Creates an array of fields that can be mapped to
 */
function sms_receive_type_fields($node_type) {
  $field_mappers = array(
    NULL => '',
    // This is the empty choice
    'title' => t('title'),
    'body' => t('body'),
  );
  if (module_exists('content')) {
    $fields = content_fields();
    foreach ($fields as $field) {
      if ($field['type_name'] == $node_type) {
        $field_mappers[$field['field_name']] = $field['field_name'];
      }
    }
  }
  return $field_mappers;
}

/**
 * Hook for gateways to define how incoming messages are parsed
 */
function sms_receive_parse() {
  $gateway = variable_get('sms_default_gateway', 0);
  $function = 'sms_' . $gateway . '_receive_parse';
  if (function_exists($function)) {
    $sms_message = $function();
  }
  return $sms_message;
}

/**
 * Hook for gateways to define incoming fields
 */
function sms_receive_sms_fields() {

  // Maybe 'from' and 'text' should be built-in fields and
  // this is used to collect extra fields, in our case 'type'
  $gateway = variable_get('sms_default_gateway', 0);
  $function = 'sms_' . $gateway . '_receive_fields';
  if (function_exists($function)) {
    $fields = $function();
  }
  return $fields;
}

/**
 * Implements hook_perm()
 */
function sms_receive_perm() {
  return array(
    'receive sms message',
  );
}

/*
 * Handle a received message
 * Loosely based on mailhandler_retreive()
 */
function sms_receive_receive() {
  $message = sms_receive_parse();

  // Insert message into database, mostly for logging and debug right now
  $mid = db_next_id('{sms_messages}');
  db_query("INSERT INTO {sms_receive} (mid, number, message, time) VALUES(%d, '%s', '%s', '%s')", $mid, $message['from'], $message['text'], time());
  $node = sms_receive_process_message($message);

  // check if mail originates from an authenticated user
  // Can't do this as a hook to sms_user because we need to authenticate as this user
  $node = sms_receive_authenticate($node, $message);

  // we need to change the current user
  // this has to be done here to allow modules
  // to create users
  sms_receive_switch_user($node->uid);

  // modules may override node elements before submitting. they do so by returning the node.
  foreach (module_list() as $name) {
    if (module_hook($name, 'sms_receive')) {
      $function = $name . '_sms_receive';
      if (!($node = $function($node, $message))) {

        // Exit if a module has handled the submitted data.
        break;
      }
    }
  }
  if ($node) {
    if ($node->type == 'comment') {
      sms_receive_comment_submit($node);
    }
    else {
      sms_receive_node_submit($node);
    }
  }

  // switch back to original user
  sms_receive_switch_user();

  // Show what was received, mostly for debugging
  $output = 'Type: ' . $message['type'] . '<br />From: ' . $message['from'] . '<br />Text: ' . $message['text'];
  return $output;
}

/**
 * Based on mailhandler_process_message() but heavily modified
 * Creates and return node object
 */
function sms_receive_process_message($sms_message) {
  $content_type = variable_get('sms_receive_content_type', 'page');
  $node_fields = sms_receive_type_fields($content_type);
  $sms_fields = sms_receive_sms_fields();

  // Create a new node and set its options
  $node = new stdClass();
  $node->type = $content_type;
  $node_options = variable_get('node_options_' . $content_type, array(
    'status',
  ));
  foreach ($node_options as $node_option) {
    $node->{$node_option} = 1;
  }

  // Put the received data into their set fields
  foreach ($sms_fields as $sms_field) {
    if (!empty($sms_field)) {
      $node_field = variable_get('sms_receive_field_' . $sms_field, '');
      if (!empty($node_field)) {
        if ($node_field == 'title' || $node_field == 'body') {
          $node->{$node_field} = $sms_message[$sms_field];
        }
        else {
          $cck_field['0']['value'] = $sms_message[$sms_field];
          $node->{$node_field} = $cck_field;
        }
      }
    }
  }
  return $node;
}

/**
 * Loosely based on mailhandler_authenticate()
 * Determine who is the author of the upcoming node.
 */
function sms_receive_authenticate($node, $sms_message) {

  // is $sms_message['from'] a general case?
  $number = $sms_message['from'];

  // how is this be handled with international numbers? do we need to remove +44 for UK?
  // should be able to test when we get Chinese SIM card
  if (substr($number, 0, 1) == '1') {

    // remove leading '1', sms_user doesn't store it...
    $number = substr($number, 1);
  }

  // This is much cleaner, but might still be nice to use a table with phone numbers
  // ie. could query: SELECT uid FROM {sms_user} WHERE 'number' = 7785555555
  $result = db_query("SELECT uid, name FROM {users} WHERE data LIKE '%" . $number . "%'");
  while ($account = db_fetch_object($result)) {
    $node->uid = $account->uid;
    $node->name = $account->name;
    break;
  }

  // Set to anonymous if no match
  if (empty($node->uid) && empty($node->name)) {
    $node->uid = 0;
    $node->name = '';
  }
  return $node;
}

/**
 * This is verbatim from mailhandler_switch_user()
 * 
 * Switch from original user to submission user and back.
 *
 * Note: You first need to run sms_receive_switch_user without
 * argument to store the current user. Call sms_receive_switch_user
 * without argument to set the user back to the original user.
 *
 * @param $uid The user ID to switch to
 *
 */
function sms_receive_switch_user($uid = NULL) {
  global $user;
  static $orig_user = array();
  if (isset($uid)) {
    $user = user_load(array(
      'uid' => $uid,
    ));
  }
  else {
    if (count($orig_user)) {
      $user = array_shift($orig_user);
      array_unshift($orig_user, $user);
    }
    else {
      $orig_user[] = $user;
    }
  }
}

/**
 * Based on mailhandler_comment_submit()
 * Create the comment.
 */
function sms_receive_comment_submit($node) {
  if (!$node->subject) {
    $node->subject = $node->title;
  }
  if (!$node->comment) {
    $node->comment = $node->body;
  }

  // We want the comment to have the email time, not the current time
  // comment_save gets an array
  $edit = (array) $node;
}

/**
 * Based on mailhandler_node_submit()
 * Create the node.
 */
function sms_receive_node_submit($node) {
  node_validate($node);
  $error = form_get_errors();
  if (!$error) {

    // Prepare the node for save and allow modules make changes
    $node = node_submit($node);

    // Save the node
    if ($node->nid) {
      if (node_access('update', $node)) {
        node_save($node);
      }
    }
    else {
      if (node_access('create', $node)) {
        node_save($node);
      }
    }
  }
}

Functions

Namesort descending Description
sms_receive_admin_form
sms_receive_admin_form_submit
sms_receive_authenticate Loosely based on mailhandler_authenticate() Determine who is the author of the upcoming node.
sms_receive_comment_submit Based on mailhandler_comment_submit() Create the comment.
sms_receive_get_callback
sms_receive_menu
sms_receive_node_submit Based on mailhandler_node_submit() Create the node.
sms_receive_parse Hook for gateways to define how incoming messages are parsed
sms_receive_perm Implements hook_perm()
sms_receive_process_message Based on mailhandler_process_message() but heavily modified Creates and return node object
sms_receive_receive
sms_receive_set_callback
sms_receive_sms_fields Hook for gateways to define incoming fields
sms_receive_switch_user This is verbatim from mailhandler_switch_user()
sms_receive_type_fields Creates an array of fields that can be mapped to