You are here

sms_clickatell.module in SMS Framework 6

Same filename and directory in other branches
  1. 5 modules/sms_clickatell/sms_clickatell.module

Clickatell gateway module for Drupal SMS Framework. Outbound+Inbound+Receipts

Thanks to diggersf for his great work on the original module.

Applying a sender will only work with Approved Sender IDs in your Clickatell account | My Settings | Manage Sender IDs.

It is recommended that Clean URLs are on if you are using WAP PUSH, receipt functions or anything else that will handle a URL.

For inbound messaging you must configure clickatell to send messages to:

  • http(s)://yourhost.example.com/sms/clickatell/receiver

For receipts to work you must configure clickatell to send the receipt callbacks to:

  • http(s)://yourhost.example.com/sms/clickatell/receipt

The send function in this module supports several options, including message sender. Please see sms_clickatell_command()

Relevant Clickatell documentation:

@todo WAP Push functionality.

@package sms @subpackage sms_clickatell

File

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

/**
 * @file
 * Clickatell gateway module for Drupal SMS Framework. Outbound+Inbound+Receipts
 *
 * Thanks to diggersf for his great work on the original module.
 * 
 * Applying a sender will only work with Approved Sender IDs in your Clickatell
 * account | My Settings | Manage Sender IDs.
 * 
 * It is recommended that Clean URLs are on if you are using WAP PUSH, receipt
 * functions or anything else that will handle a URL.
 *
 * For inbound messaging you must configure clickatell to send messages to:
 *  - http(s)://yourhost.example.com/sms/clickatell/receiver
 *
 * For receipts to work you must configure clickatell to send the receipt callbacks to:
 *  - http(s)://yourhost.example.com/sms/clickatell/receipt
 *
 * The send function in this module supports several options, including message
 * sender. Please see sms_clickatell_command()
 *
 * Relevant Clickatell documentation:
 *  - https://www.clickatell.com/developers/api_http.php
 *  - https://www.clickatell.com/downloads/http/Clickatell_HTTP.pdf
 *  - http://www.clickatell.com/downloads/Clickatell_two-way_technical_guide.pdf
 * 
 * @todo WAP Push functionality.
 *
 * @package sms
 * @subpackage sms_clickatell
 */

/**
 * Implement hook_gateway_info()
 *
 * @return
 *   SMS Framework gateway info array
 *
 * @ingroup hooks
 */
function sms_clickatell_gateway_info() {
  return array(
    'clickatell' => array(
      'name' => 'Clickatell',
      'send' => 'sms_clickatell_send',
      'configure form' => 'sms_clickatell_admin_form',
      'message_status_codes' => 'sms_clickatell_message_status_codes',
      'response_codes' => 'sms_clickatell_response_codes',
    ),
  );
}

/**
 * Implement hook_menu()
 *
 * @return
 *   Drupal menu items array
 *
 * @ingroup hooks
 */
function sms_clickatell_menu() {
  $items = array();
  $items['sms/clickatell/receiver'] = array(
    'title' => 'Clickatell SMS message receiver',
    'page callback' => 'sms_clickatell_receive_message',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['sms/clickatell/receipt'] = array(
    'title' => 'Clickatell SMS receipt receiver',
    'page callback' => 'sms_clickatell_receive_receipt',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Configuration form for gateway module
 *
 * @param $configuration
 *
 * @return
 *   Drupal form array
 */
function sms_clickatell_admin_form($configuration) {
  $form['sms_clickatell_balance'] = array(
    '#type' => 'item',
    '#title' => t('Current balance'),
    '#value' => sms_clickatell_balance(),
  );
  $form['sms_clickatell_ssl'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use SSL Encyption'),
    '#description' => t('Drupal\'s built-in HTTP client only supports SSL on PHP 4.3 compiled with OpenSSL.'),
    '#default_value' => $configuration['sms_clickatell_ssl'],
  );
  $form['sms_clickatell_api_id'] = array(
    '#type' => 'textfield',
    '#title' => t('API ID'),
    '#description' => t('Clickatell issues this number upon addition of an HTTP sub-product to your account.'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => $configuration['sms_clickatell_api_id'],
  );
  $form['sms_clickatell_user'] = array(
    '#type' => 'textfield',
    '#title' => t('User'),
    '#description' => t('The username of your Clickatell account.'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => $configuration['sms_clickatell_user'],
  );
  $form['sms_clickatell_password'] = array(
    '#type' => 'textfield',
    '#title' => t('Password'),
    '#description' => t('The current password on your Clickatell account.'),
    '#size' => 30,
    '#maxlength' => 64,
    '#default_value' => $configuration['sms_clickatell_password'],
  );
  $form['sms_clickatell_from'] = array(
    '#type' => 'textfield',
    '#title' => t('Default Sender (from)'),
    '#description' => t('Name/number of the default sender. Will be used if a sender is not specified on message send.<br /><em>This will only work with <strong>Approved</strong> Sender IDs in your Clickatell account | My Settings | Manage Sender IDs.</em><br />A valid international format number up to 16 characters (eg: 447911222333) or alphanumeric string of 11 characters (eg: My Service).<br />If empty / sender not specified on message send / not Approved Seender ID, then Clickatell will apply a gateway number.'),
    '#size' => 16,
    '#maxlength' => 16,
    '#default_value' => $configuration['sms_clickatell_from'],
  );
  $form['sms_clickatell_callback'] = array(
    '#type' => 'select',
    '#title' => t('Status Callback (delivery receipts)'),
    '#description' => t('Enable delivery receipts when message status changes in the gateway.'),
    '#multiple' => FALSE,
    '#options' => array(
      0 => t('No message status returned'),
      1 => t('Return only intermediate statuses'),
      2 => t('Return only final statuses of a message'),
      3 => t('Return both intermediate and final stauses of a message'),
    ),
    '#default_value' => $configuration['sms_clickatell_callback'],
  );
  return $form;
}
function sms_clickatell_admin_form_validate($form, &$form_state) {

  // Check default sender
  if (!empty($form_state['values']['sms_clickatell_from'])) {
    if (!is_numeric($form_state['values']['sms_clickatell_from'])) {
      if (strlen($form_state['values']['sms_clickatell_from']) > 11) {
        form_set_error('sms_clickatell_from', t('An alphanumeric sender is limited to a maximum of 11 characters.'));
      }
    }
  }

  // Attempt a connection with the given credentials
  $result = sms_clickatell_command('auth', array(), $form_state['values']);
  if (!$result['status']) {
    form_set_error('', t('A Clickatell gateway error occured: @code: @text', array(
      '@code' => $result['gateway_status_code'],
      '@text' => $result['gateway_status_text'],
    )));
  }
  variable_set('sms_clickatell_session_id_timestamp', 0);
}

/**
 * Callback for sending messages.
 *
 * Options for this send function: see sms_txtlocal_command()
 *
 * @param $number
 *   MSISDN of message recipient. Expected to include the country code prefix.
 * @param $message
 *   Message body text.
 * @param $options
 *   Options from SMS Framework.
 *
 * @return
 *   Response from sms_clickatell_command()
 */
function sms_clickatell_send($number, $message, $options) {

  // Attach the country code to the number, if required
  if (array_key_exists('country', $options)) {
    $number = $options['country'] . $number;
  }
  return sms_clickatell_command('sendmsg', array(
    'number' => $number,
    'message' => $message,
    'options' => $options,
  ));
}

/**
 * Get account balance
 *
 * @return
 *   Balance text
 */
function sms_clickatell_balance() {
  $result = sms_clickatell_command('getbalance');

  // This part of the array will either contain the balance or a useful error message
  return $result['gateway_status_text'];
}

/**
 * Executes a command using the Clickatell API
 *
 * data array fields:
 *   number  - MSISDN of message recipient. Purely numeric and must begin with intl prefix, eg. 4477121231234.
 *   message - Message text. Max 459 chars (3x SMS). Use %n for newline.
 *   options - Array of additional options, as below.
 *
 * data['options'] array fields:
 *   sender      - Optional: Sender ID may be an MSISDN (max 16 chars) or an alphanumeric string (max 11 chars). See note about Approved Sender IDs in the header of this file. Clickatell param: 'from'
 *   reference   - Optional: Reference tag to apply to message. Will appear on any receipt. No spaces. Clickatell param: 'cliMsgId'
 *   delaymins   - Optional: Delay message sending by N minutes. Clickatell param: 'deliv_time'
 *   expiremins  - Optional: The message send will abort if not sent within N minutes. Clickatell param: 'validity'
 *   priority    - Optional: Queue priority to apply to the message. Can be 1, 2 or 3, where 1 is high priority. Clickatell param: 'queue'
 *   expectreply - Optional: Route the message properly so that the user can reply. Clickatell param: 'mo'
 *
 * @param $command
 *   One of 'auth', 'sendmsg' or 'getbalance'.
 * @param $data
 *   All data required to perform the command.
 * @param $config
 *   Gateway configuration parameters.
 *
 * @return
 *   Response from command.
 */
function sms_clickatell_command($command = 'auth', $data = array(), $config = NULL) {
  $gateway = sms_gateways('gateway', 'clickatell');
  if ($config == NULL) {
    $config = $gateway['configuration'];
  }
  if ($config['sms_clickatell_ssl']) {
    $scheme = 'https';
  }
  else {
    $scheme = 'http';
  }
  switch ($command) {
    case 'auth':
      $query = 'api_id=' . $config['sms_clickatell_api_id'] . '&user=' . $config['sms_clickatell_user'] . '&password=' . $config['sms_clickatell_password'];
      break;
    case 'sendmsg':

      // Check if the message requires unicode handling
      if ($unicode_message = sms_clickatell_unicode($data['message'])) {
        $message = $unicode_message;
      }
      else {
        $message = drupal_urlencode($data['message']);
      }
      $query = 'session_id=' . sms_clickatell_get_session_id() . '&to=' . $data['number'] . '&text=' . $message;

      // Check if the message requires concatenation (long messages)
      // Note: concatenation over multiple messages reduces each SMS message length by 7 chars.
      $concat = 1;
      if (strlen($message) > 160) {
        $concat = 2;
        if (strlen($message) > 306) {
          $concat = 3;
        }
      }
      $query .= '&concat=' . $concat;

      // Add any optional arguments
      if (isset($data) && array_key_exists('options', $data)) {

        // sender (Clickatell: from)
        if (array_key_exists('sender', $data['options'])) {
          $query .= '&from=' . $data['options']['sender'];
          $sender_set = TRUE;
        }

        // delaymins (Clickatell: deliv_time)
        if (array_key_exists('delaymins', $data['options']) && $data['options']['delaymins'] >= 10 && $data['options']['delaymins'] <= 10080) {
          $query .= '&deliv_time=' . $data['options']['delaymins'];
        }

        // priority (Clickatell: queue)
        if (array_key_exists('priority', $data['options']) && $data['options']['priority'] >= 1 && $data['options']['priority'] <= 3) {
          $query .= '&queue=' . $data['options']['priority'];
        }

        // expiremins (Clickatell: validity)
        if (array_key_exists('expiremins', $data['options']) && $data['options']['expiremins'] >= 1 && $data['options']['expiremins'] <= 1440) {
          $query .= '&validity=' . $data['options']['expiremins'];
        }

        // reference (Clickatell: cliMsgId)
        if (array_key_exists('reference', $data['options']) && strlen($data['options']['reference']) <= 32) {
          $query .= '&cliMsgId=' . $data['options']['reference'];
        }

        // expectreply (Clickatell: mo)
        if (array_key_exists('expectreply', $data['options'])) {
          $query .= '&mo=' . $data['options']['expectreply'];
        }
      }

      // If sender is not set and default sender exists, then apply default sender
      if (!isset($sender_set) && $config['sms_clickatell_from']) {
        $query .= '&from=' . $config['sms_clickatell_from'];
      }

      // Apply callback parameter if set
      if ($config['sms_clickatell_callback']) {
        $query .= '&callback=' . $config['sms_clickatell_callback'];
      }
      break;
    case 'getbalance':
      $query = 'session_id=' . sms_clickatell_get_session_id();
      break;
  }

  // Run the command
  $http_result = drupal_http_request($scheme . '://api.clickatell.com/http/' . $command . '?' . $query);

  // Check for HTTP errors
  if ($http_result->error) {
    return array(
      'status' => FALSE,
      'message' => t('An error occured during the HTTP request: @error', array(
        '@error' => $http_result->error,
      )),
    );
  }
  if ($http_result->data) {

    // Check for Clickatell errors
    if (preg_match('/^ERR: ([\\d]+), (([\\w]|[\\s])+)$/', $http_result->data, $matches)) {
      $errorcode = $matches[1];
      $errortext = $matches[2];
      $result = array(
        'status' => FALSE,
        'status_code' => sms_clickatell_map_response_code($errorcode),
        'gateway_status_code' => $errorcode,
        'gateway_status_text' => $errortext,
      );
    }
    elseif ($command == 'auth') {

      // Add Clickatell session ID to result array.
      list($status, $sid) = explode(': ', $http_result->data);
      $result = array(
        'status' => TRUE,
        'status_code' => SMS_GW_OK,
        'sid' => $sid,
      );
    }
    elseif ($command == 'getbalance') {

      // Add Clickatell credit balance to result array.
      preg_match('/Credit:[\\s]+([\\d]+\\.*[\\d]+)$/', $http_result->data, $matches);
      $result = array(
        'status' => TRUE,
        'status_code' => SMS_GW_OK,
        'gateway_status_text' => $matches[1],
      );
    }
    else {

      // Return a good response array
      $result = array(
        'status' => TRUE,
        'status_code' => SMS_GW_OK,
      );
    }
  }
  return $result;
}

/**
 * Get a new or existing Clickatell session ID
 *
 * @return
 *   Clickatell session ID
 */
function sms_clickatell_get_session_id() {
  if (variable_get('sms_clickatell_session_id_timestamp', 0) < strtotime('-10 mins')) {
    if ($result = sms_clickatell_command()) {
      if ($result['status']) {
        variable_set('sms_clickatell_session_id', $result['sid']);
        variable_set('sms_clickatell_session_id_timestamp', time());
        watchdog('sms', 'Clickatell session ID refreshed: %sid', array(
          '%sid' => $result['sid'],
        ));
      }
    }
  }
  return variable_get('sms_clickatell_session_id', 0);
}

/**
 * Receive an SMS message and pass it into the SMS Framework
 *
 * Will generate an $options array with the following variables:
 *   receiver  - The destination MSISDN number. Clickatell param: 'to'
 *   reference - The message ID code that refers to a message originally sent with the 'expectreply' or 'mo' parameter. Clickatell param: 'moMsgId'
 * For raw gateway params see Clickatell_two-way_technical_guide.pdf page 9.
 *
 * I have neglected the Clickatell 'timestamp' param because it is passed in non-UTC
 * timezone and is in MySQL format. It is more useful to capture a timestamp in your
 * hook_sms_incoming() function.
 */
function sms_clickatell_receive_message() {
  $number = $_REQUEST['from'];
  $message = $_REQUEST['text'];
  $options = array();

  // Define raw gateway response parameters
  $options['gateway_params'] = array();
  if (array_key_exists('to', $_REQUEST) && !empty($_REQUEST['to'])) {
    $options['gateway_params']['to'] = $_REQUEST['to'];
  }
  if (array_key_exists('api_id', $_REQUEST) && !empty($_REQUEST['api_id'])) {
    $options['gateway_params']['api_id'] = $_REQUEST['api_id'];
  }
  if (array_key_exists('moMsgId', $_REQUEST) && !empty($_REQUEST['moMsgId'])) {
    $options['gateway_params']['moMsgId'] = $_REQUEST['moMsgId'];
  }

  // Define message receiver and reference in options array
  $options['receiver'] = array_key_exists('to', $_REQUEST) ? $_REQUEST['to'] : '';
  $options['reference'] = array_key_exists('moMsgId', $_REQUEST) ? $_REQUEST['moMsgId'] : '';
  sms_incoming($number, $message, $options);
}

/**
 * Receive a message receipt from Clickatell
 *
 * Will generate an $options array with the following variables:
 *   reference - A message reference code, if set on message send. Clickatell param: 'cliMsgId'
 *   receiver  - The destination MSISDN number. Clickatell param: 'to'
 *   gateway_message_status      - A Clickatell message status code.
 *   gateway_message_status_text - A text string associated with the gateway_status.
 * For raw gateway params see Clickatell_HTTP.pdf page 10.
 *
 * Note that there may be >1 receipt for a message that takes time to be delivered.
 *
 * I have neglected the Clickatell 'timestamp' param because it is passed in non-UTC
 * timezone and is in MySQL format. It is more useful to capture a timestamp in your
 * hook_sms_receipt() function.
 */
function sms_clickatell_receive_receipt() {
  $number = array_key_exists('from', $_REQUEST) ? $_REQUEST['from'] : NULL;
  $reference = array_key_exists('cliMsgId', $_REQUEST) ? $_REQUEST['cliMsgId'] : NULL;
  $gw_msg_status_code = array_key_exists('status', $_REQUEST) ? $_REQUEST['status'] : SMS_MSG_STATUS_UNKNOWN;
  $options = array();

  // Define raw gateway receipt call parameters
  $options['gateway_params'] = array();
  if (array_key_exists('to', $_REQUEST) && !empty($_REQUEST['to'])) {
    $options['gateway_params']['to'] = $_REQUEST['to'];
  }
  if (array_key_exists('api_id', $_REQUEST) && !empty($_REQUEST['api_id'])) {
    $options['gateway_params']['api_id'] = $_REQUEST['api_id'];
  }
  if (array_key_exists('moMsgId', $_REQUEST) && !empty($_REQUEST['moMsgId'])) {
    $options['gateway_params']['moMsgId'] = $_REQUEST['moMsgId'];
  }
  if (array_key_exists('charge', $_REQUEST) && !empty($_REQUEST['charge'])) {
    $options['gateway_params']['charge'] = $_REQUEST['charge'];
  }
  if (array_key_exists('cliMsgId', $_REQUEST) && !empty($_REQUEST['cliMsgId'])) {
    $options['gateway_params']['cliMsgId'] = $_REQUEST['cliMsgId'];
  }

  // Define message receiver and reference in options array
  $options['receiver'] = array_key_exists('to', $_REQUEST) ? $_REQUEST['to'] : '';
  $options['reference'] = $reference;

  // Get framework message status code and Clickatell status text
  $status = sms_clickatell_map_message_status_code($gw_msg_status_code);
  $gw_msg_status_codes = sms_clickatell_message_status_codes();
  $gw_msg_status_text = $gw_msg_status_codes[$gw_msg_status_code];

  // Define gateway-specific status (code) and text (success/error message)
  $options['gateway_message_status'] = $gw_msg_status_code;
  $options['gateway_message_status_text'] = $gw_msg_status_text;

  // Invoke the SMS Framework receipt handler
  sms_receipt($number, $reference, $status, $options);
}

/**
 * Map a Clickatell message status code to an SMS Framework message status code
 *
 * @return
 *   SMS Framework message status code. See sms constants.
 */
function sms_clickatell_map_message_status_code($code) {
  switch ($code) {
    case '003':
    case '004':
      return SMS_MSG_STATUS_DELIVERED;
    case '002':
    case '011':
      return SMS_MSG_STATUS_QUEUED;
    case '008':
      return SMS_MSG_STATUS_OK;
    case '001':
    case '005':
    case '006':
    case '007':
    case '009':
      return SMS_MSG_STATUS_ERROR;
    case '010':
      return SMS_MSG_STATUS_EXPIRED;
    case '012':
      return SMS_MSG_STATUS_NOCREDIT;
    default:
      return SMS_MSG_STATUS_UNKNOWN;
  }
}

/**
 * Map a Clickatell gateway response status code to an SMS Framework gateway status code
 *
 * @return
 *   SMS Framework gateway status code. See sms constants.
 */
function sms_clickatell_map_response_code($code) {
  switch ($code) {
    case '001':
    case '002':
    case '003':
    case '004':
    case '005':
    case '007':
      return SMS_GW_ERR_AUTH;
    case '101':
    case '102':
    case '105':
    case '106':
    case '107':
    case '108':
    case '109':
    case '111':
    case '112':
    case '116':
    case '120':
    case '123':
    case '201':
    case '202':
      return SMS_GW_ERR_INVALID_CALL;
    case '103':
    case '104':
      return SMS_GW_ERR_NOT_FOUND;
    case '113':
      return SMS_GW_ERR_MSG_LIMITS;
    case '114':
      return SMS_GW_ERR_MSG_ROUTING;
    case '110':
      return SMS_GW_ERR_MSG_OTHER;
    case '115':
      return SMS_GW_ERR_MSG_QUEUING;
    case '121':
    case '122':
    case '128':
      return SMS_GW_ERR_DEST_NUMBER;
    case '301':
    case '302':
      return SMS_GW_ERR_CREDIT;
    default:
      return SMS_GW_ERR_OTHER;
  }
}

/**
 * Returns an array of message status codes and strings that are generated by the Clickatell gateway
 *
 * Clickatell always uses leading zeros, so its important to enclose the code
 * keys in quotes.
 *
 * @return
 *   Associative array of message status codes and text strings.
 */
function sms_clickatell_message_status_codes() {
  return array(
    '001' => 'Message unknown',
    '002' => 'Message queued',
    '003' => 'Delivered to gateway',
    '004' => 'Received by recipient',
    '005' => 'Error with message',
    '006' => 'User cancelled message delivery',
    '007' => 'Error delivering message',
    '008' => 'OK',
    '009' => 'Routing error',
    '010' => 'Message expired',
    '011' => 'Message queued for later delivery',
    '012' => 'Out of credit',
  );
}

/**
 * Returns an array of response codes and messages that are generated by the Clickatell gateway
 *
 * @return
 *   Associative array of response codes and text.
 */
function sms_clickatell_response_codes() {
  return array(
    '001' => 'Authentication failed',
    '002' => 'Unknown username or password',
    '003' => 'Session ID expired',
    '004' => 'Account frozen',
    '005' => 'Missing session ID',
    '007' => 'IP Lockdown violation',
    '101' => 'Invalid or missing parameters',
    '102' => 'Invalid user data header',
    '103' => 'Unknown API message ID',
    '104' => 'Unknown client message ID',
    '105' => 'Invalid destination address',
    '106' => 'Invalid source address',
    '107' => 'Empty message',
    '108' => 'Invalid or missing API ID',
    '109' => 'Missing message ID',
    '110' => 'Error with email message',
    '111' => 'Invalid protocol',
    '112' => 'Invalid message type',
    '113' => 'Maximum message parts exceeded',
    '114' => 'Cannot route message',
    '115' => 'Message expired',
    '116' => 'Invalid Unicode data',
    '120' => 'Invalid delivery time',
    '121' => 'Destination mobile number blocked',
    '122' => 'Destination mobile opted out',
    '123' => 'Invalid Sender ID',
    '128' => 'Number delisted',
    '201' => 'Invalid batch ID',
    '202' => 'No batch template',
    '301' => 'No credit left',
    '302' => 'Max allowed credit',
  );
}

/**
 * Converts a string to USC-2 encoding if neccessary.
 *
 * @param $message
 *   Message string.
 *
 * @return
 *   Converted message string or FALSE.
 */
function sms_clickatell_unicode($message) {
  if (function_exists('iconv')) {
    $latin = @iconv('UTF-8', 'ISO-8859-1', $message);
    if (strcmp($latin, $message)) {
      $arr = unpack('H*hex', @iconv('UTF-8', 'UCS-2BE', $message));
      return strtoupper($arr['hex']) . '&unicode=1';
    }
  }
  return FALSE;
}

Functions

Namesort descending Description
sms_clickatell_admin_form Configuration form for gateway module
sms_clickatell_admin_form_validate
sms_clickatell_balance Get account balance
sms_clickatell_command Executes a command using the Clickatell API
sms_clickatell_gateway_info Implement hook_gateway_info()
sms_clickatell_get_session_id Get a new or existing Clickatell session ID
sms_clickatell_map_message_status_code Map a Clickatell message status code to an SMS Framework message status code
sms_clickatell_map_response_code Map a Clickatell gateway response status code to an SMS Framework gateway status code
sms_clickatell_menu Implement hook_menu()
sms_clickatell_message_status_codes Returns an array of message status codes and strings that are generated by the Clickatell gateway
sms_clickatell_receive_message Receive an SMS message and pass it into the SMS Framework
sms_clickatell_receive_receipt Receive a message receipt from Clickatell
sms_clickatell_response_codes Returns an array of response codes and messages that are generated by the Clickatell gateway
sms_clickatell_send Callback for sending messages.
sms_clickatell_unicode Converts a string to USC-2 encoding if neccessary.