<?php
/*
Plugin Name: Outgoing SMS
Description: Automatically send outgoing SMS messages.  Supports queueing and batching.
Version: 1.05
Requires at least: 3.00
*/

// UPDATE THESE VALUES

# You need to sign-up for an outgoing SMS Gateway service.  Enter your details for that here:
$GLOBALS['OUTGOING_SMS_GATEWAY']                            = 'amazon.com'; // Supported Gatways: txtlocal.com, twilio.com and amazon.com (Ask us for support for your gateway)
$GLOBALS['OUTGOING_SMS_GATEWAY_USERNAME_OR_API_KEY']        = $GLOBALS['SETTINGS']['aws']['key']; // If using txtlocal.com; enter your username. If using amazon or twilio; enter your API key.
$GLOBALS['OUTGOING_SMS_GATEWAY_PASSWORD_OR_API_KEY_SECRET'] = $GLOBALS['SETTINGS']['aws']['secret']; // If using txtlocal.com; enter your password. If using aws.amazon.com or twilio.com; enter your API key secret.
$GLOBALS['OUTGOING_SMS_GATEWAY_PHONE_NUMBER']               = ''; // TWILIO ONLY: Add your twilio phone number here. If in test mode, the standard twilio test phone number will be used. You can purchase a phone number here: https://www.twilio.com/console/phone-numbers/search
// these options allow you to send SMS messages from CMS list views.
$GLOBALS['OUTGOING_SMS_SEND_ACCESS_REQ'] = 'admin';  // controls who is allow to send SMS messages via "Advanced Commands..." menu.  Must be: admin, editor, or blank "" to hide this option
$GLOBALS['OUTGOING_SMS_PHONE_FIELD']     = 'mobile'; // if this field exists and above option is set then "Send SMS" option will appear in "Advanced Options..." menus.

// DON'T UPDATE ANYTHING BELOW THIS LINE

$GLOBALS['OUTGOING_SMS_GATEWAY_TESTMODE'] = false;    // tell gateway to use testmode and not actually send messages
$GLOBALS['OUTGOING_SMS_MAX_MESSAGES']     = '5';      // max messages to send at once with cronjob script, leave blank for unlimited

$GLOBALS['OUTGOING_SMS_PLUGIN']           = true;
$GLOBALS['OUTGOING_SMS_TABLENAME']        = '_outgoing_sms';
$GLOBALS['OUTGOING_SMS_ERRORS']           = '';

addAction('admin_postlogin',         '_outgoingSMS_setup_createSchema',      null, 0);
addAction('section_preDispatch',     '_outgoingSMS_advancedOption_dispatch', null, 2);
addFilter('listHeader_displayLabel', '_outgoingSMS_cmsEditor_summaryColumn', null, 4);
addFilter('listRow_displayValue',    '_outgoingSMS_cmsEditor_summaryColumn', null, 4);
addFilter('list_advancedCommands',   '_outgoingSMS_advancedOption_addLink',  null, 1);

// CMS: add plugin hooks & handlers
pluginAction_addHandlerAndLink('Send Queued Messages', 'outgoingSMS_sendQueuedMessages', true);
pluginAction_addHandlerAndLink('Send Test SMS',        '_outgoingSMS_sendForm',          true);

// Schedule Task/Cronjob
addCronJob('outgoingSMS_sendQueuedMessages',"Send Queued Outgoing SMS Messages",'* * * * *'); // Run every minute

// queue message or return errors
// list($errors, $responseArray) = outgoingSMS_queueMessage($from, $to, $text);
function outgoingSMS_queueMessage($from, $to, $text) {
  $response = array();

  // error checking
  $sendErrors = _outgoingSMS_messageErrorChecking($from, $to, $text);

  // add message to database
  if (!$sendErrors) {
    $insertArray = [
      'createdDate' => mysql_datetime(),
      'from'        => $from,
      'to'          => $to,
      'text'        => $text,
    ];
    $recordNum = mysql_insert($GLOBALS['OUTGOING_SMS_TABLENAME'], $insertArray);

    $response['result']    = 'Added to queue';
    $response['tablename'] = $GLOBALS['OUTGOING_SMS_TABLENAME'];
    $response['recordnum'] = $recordNum;
  }

  //
  return array($sendErrors, $response);
}

// send an SMS message, returns errors or nothing on success
// list($sendErrors, $response) = outgoingSMS_sendMessage($from, $to, $text);
function outgoingSMS_sendMessage($from, $to, $text) {
  $validGateways = array('txtlocal.com', 'twilio.com', 'amazon.com');
  $sendErrors    = '';
  $response      = [];

  // error checking
  $sendErrors = _outgoingSMS_messageErrorChecking($from, $to, $text);

  // Send message
  if (!$sendErrors) {

    ### txtlocal.com
    if ($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'txtlocal.com') {
      // API Docs: http://www.txtlocal.co.uk/developers/docs/
      $url    = 'http://www.txtlocal.com/sendsmspost.php';
      $params = [
        'test'          => ($GLOBALS['OUTGOING_SMS_GATEWAY_TESTMODE'] ? '1' : '0'), //
        'info'          => 0, // either info or json can be set, or neither, but not both
        'json'          => 1, // either info or json can be set, or neither, but not both
        'uname'         => $GLOBALS['OUTGOING_SMS_GATEWAY_USERNAME_OR_API_KEY'],
        'pword'         => $GLOBALS['OUTGOING_SMS_GATEWAY_PASSWORD_OR_API_KEY_SECRET'],
        'selectednums'  => $to,
        'from'          => $from,
        'message'       => $text,
        // Note: API Docs say newline chars bust be sent as %n but it doesn't seem to matter, use line below if needed
        //'message'       => str_replace("\n", "%n", $text), // newline chars must be sent as %n as per API docs
      ];
      $query = $url . '?' . http_build_query($params);
      list($json, $httpStatusCode) = getPage($query);

      $response   = json_decode($json, true);
      $sendErrors = @$response['ERROR'];
    
    }elseif($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'twilio.com') {
      //Set either the test phone number or the live one (if the user has one.
      $fromPhoneNumber = ($GLOBALS['OUTGOING_SMS_GATEWAY_TESTMODE'])? '+15005550006' : $GLOBALS['OUTGOING_SMS_GATEWAY_PHONE_NUMBER'] ;
      if(!$fromPhoneNumber) { trigger_error("You have not set a Twilio phone number! Either set the Outgoing SMS plugin to test mode and use your test credentials, or add a phone number to the global \$GLOBALS['OUTGOING_SMS_GATEWAY_PHONE_NUMBER']", E_USER_WARNING); exit;}
      //Set up the post data to be sent.
      $postData        = [
        'To'   => $to,
        'Body' => $text,
        'From' => $fromPhoneNumber,
      ];
      $baseUrl = "https://{$GLOBALS['OUTGOING_SMS_GATEWAY_USERNAME_OR_API_KEY']}:{$GLOBALS['OUTGOING_SMS_GATEWAY_PASSWORD_OR_API_KEY_SECRET']}@api.twilio.com/2010-04-01/Accounts/{$GLOBALS['OUTGOING_SMS_GATEWAY_USERNAME_OR_API_KEY']}/";

      //Carry out API call.
      list($html, $httpStatusCode, $headers, $request) =  getPage($baseUrl."Messages.json?". http_build_query($postData) ,  5, array(), true, '');
      $response = json_decode($html, true);

      //Handle the various error code types here:
      if(@$response['error_code']){
        $sendErrors = "#{$response['error_code']} : {$response['error_message']}<br>\n";  
      }elseif(@$response['code']){
        $sendErrors = "#{$response['code']} : {$response['message']}<br>\n";   
      }

    }elseif($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'amazon.com'){
      //Set the raw variabels.
      $domain        = "sns.us-east-1.amazonaws.com";
      $timeStamp     = date("Y-m-d\TH:i:s");
      $urlVariables = [
        "AWSAccessKeyId"   => $GLOBALS['OUTGOING_SMS_GATEWAY_USERNAME_OR_API_KEY'],
        "Action"           => "Publish",
        "Message"          => $text,
        "PhoneNumber"      => $to,
        "SignatureMethod"  => "HmacSHA256",
        "SignatureVersion" => "2",
        "SMSType"          => "Transactional",
        "Timestamp"        => $timeStamp,
        'Version'          => '2010-03-31'
      ];
      ksort($urlVariables); //The signaturure requires that URL variables be sorted in byte order.
      //Create the URL string.
      $canonicalizedQuery = [];
      foreach($urlVariables as $variableName => $variableValue){
        $canonicalizedQuery[] = $variableName."=".rawurlencode($variableValue);
      }
      $canonicalizedQuery = implode("&", $canonicalizedQuery);
      //Create the hashString that proves the request hasn't been tampered with.
      $hashString      = "POST\n";
      $hashString     .= "$domain\n";
      $hashString     .= "/\n";
      $hashString     .= $canonicalizedQuery;
      //Create the signature
      $signature       = hash_hmac('sha256', $hashString, $GLOBALS['OUTGOING_SMS_GATEWAY_PASSWORD_OR_API_KEY_SECRET'], true);
      $base64Signature = base64_encode($signature);
      //Send the request to send the SMS
      $url = 'https://'.$domain."?".$canonicalizedQuery."&Signature=".rawurlencode($base64Signature);
      list($xml, $httpStatusCode, $headers, $request) =  getPage($url, 5, array(), true, '');
      $returnedData      = simplexml_load_string($xml);
      //Process the returned data
      if(isset($returnedData->Error)) {
        $sendErrors .= @"{$returnedData->Error->Type} - ";
        $sendErrors .= @"{$returnedData->Error->Code} - ";
        $sendErrors .= @"{$returnedData->Error->Message}";
      }
      $response = [
        'messageId' => @"{$returnedData->PublishResult->MessageId}",
        'requestId' => @"{$returnedData->ResponseMetadata->RequestId}",
      ];
    }


    ### *** Add new gateways here ***
    elseif ($GLOBALS['OUTGOING_SMS_GATEWAY'] == '***NEW GATEWAY***') {
      // ...
      // ...
      // ...
    }

    ### error checking
    else {
      $error = "Invalid gateway '{$GLOBALS['OUTGOING_SMS_GATEWAY']}'. Valid options: " . implode(', ', $validGateways);
      return [$error, $response];
    }
  }

  //
  return array($sendErrors, $response);
}

//
function outgoingSMS_countQueuedMessages() {
  $count = mysql_count( $GLOBALS['OUTGOING_SMS_TABLENAME'] );
  return $count;
}

// list($messagesSent, $errors) = outgoingSMS_sendQueuedMessages();
// stops on errors
function _outgoingSMS_sendQueuedMessages() {
  global $TABLE_PREFIX;
  $tableName = $GLOBALS['OUTGOING_SMS_TABLENAME'];

  // load new messages (one at a time)
  $query      = "SELECT * FROM `$tableName` LIMIT 1";
  $max        = $GLOBALS['OUTGOING_SMS_MAX_MESSAGES'];
  $count      = 0;
  $errors     = '';
  $lockName   = $GLOBALS['OUTGOING_SMS_TABLENAME'] . '_lock';

  while (1) {
    if ($max && $count >= $max) { break; }

    // lock table
    if (!mysql_get_lock($lockName)) { return array(0, 'Aborting, another sms process is still running'); } // if already locked, another process is still running so abort

    // load next message
    $record = mysql_get($tableName, null, "TRUE");
    if (!$record) { break; }

    // send message
    print "Sending message #{$record['num']} to {$record['to']}\n";
    list($errors) = outgoingSMS_sendMessage($record['from'], $record['to'], $record['text']);

    // delete outgoing message record
    if (!$errors) { mysql_delete($tableName, $record['num']); }

    // unlock table
    mysql_release_lock($lockName);

    //
    if ($errors) { break; } // abort if errors
    $count++;
  }

  //
  $messagesSent = $count;
  return array($messagesSent, $errors);
}


// return errors with message content
function _outgoingSMS_messageErrorChecking($from, $to, $text) {
  $sendErrors = '';

  //
  $toLength   = strlen($to);
  $fromLength = strlen($from);
  $textLength = strlen($text);
  $isTwilio   = ($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'twilio.com');
  $isTxtlocal = ($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'txtlocal.com');
  $isAmazon   = ($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'amazon.com');

  if     (!@$to)                             { $sendErrors .= "No 'to' value specified in message!\n"; }
  if($isTxtlocal || $isTxtlocal) {
    if (preg_match("/[^0-9]+/", $to))        { $sendErrors .= "Message 'to' can only contain numbers (was '" .htmlencode($to). "')!\n"; }
  }elseif($isAmazon) {
    if (preg_match("/[^0-9]\++/", $to))      { $sendErrors .= "Message 'to' can only contain numbers or + (was '" .htmlencode($to). "')!\n"; }
    elseif(!startsWith('+', $to))            { $sendErrors .= "Message 'to' must start with a '+'!\n"; }
  }
  if($isTxtlocal) {
    if     (!@$from )                            { $sendErrors .= "No 'from' value specified in message!\n"; }
    elseif (3 > $fromLength || $fromLength > 11) { $sendErrors .= "Message 'from' must be between 3 and 11 chars ($fromLength chars)!\n"; }
  }
  elseif (preg_match("/[^\w ]+/", $from))      { $sendErrors .= "Message 'from' can only be alphanumeric or spaces (was '" .htmlencode($from). "')!\n"; }
  if     (!@$text)                             { $sendErrors .= "No 'text' value specified in message!\n"; }
  elseif ($textLength > 160)                   { $sendErrors .= "Message 'text' can't be longer than 160 chars ($textLength chars)!\n"; }

  //
  return $sendErrors;
}

//
function _outgoingSMS_cmsEditor_summaryColumn($displayValue, $tableName, $fieldname, $record = array()) {
  if ($tableName != $GLOBALS['OUTGOING_SMS_TABLENAME']) { return $displayValue; } // skip all by our table
  if ($fieldname != '_message_summary_')                { return $displayValue; } // skip all but pseudo-field

  // header - we detect the header hook by checking if the 4th argument is set
  if (!$record) {
    return t("Messages");
  }

  // row cell - we detect the row cell by checking if $record is set
  $output = "
  <table border='0' cellspacing='0' cellpadding='0' class='spacedTable'>
   <tr><td><b>" .t('Date').    "</b></td><td>&nbsp:&nbsp;</td><td>" .htmlencode($record['createdDate']). "</td></tr>
   <tr><td><b>" .t('From').    "</b></td><td>&nbsp:&nbsp;</td><td>" .htmlencode($record['from']).        "</td></tr>
   <tr><td><b>" .t('To').      "</b></td><td>&nbsp:&nbsp;</td><td>" .htmlencode($record['to']).          "</td></tr>
   <tr><td><b>" .t('Text').    "</b></td><td>&nbsp:&nbsp;</td><td>" .nl2br(htmlencode($record['text'])). "</td></tr>
  </table>\n";
  return $output;
}

//
function _outgoingSMS_setup_createSchema() {
  $tableName  = $GLOBALS['OUTGOING_SMS_TABLENAME'];
  $sourcePath = __DIR__ . "/$tableName.ini.php";
  createSchemaFromFile( $sourcePath );
}

//Send the queued messages 
function outgoingSMS_sendQueuedMessages() {

  if (!inCLI()) {
    if (!headers_sent()) { 
      header("Content-type: text/plain");
      header("Content-Disposition: inline; filename='output.txt'");
      ob_disable();
    }
    ignore_user_abort( true );
    session_write_close();
  }
  set_time_limit(0);

  $pendingMessages = outgoingSMS_countQueuedMessages();
  #if (!$pendingMessages) { die("No new messages to send!"); }
  print "Sending out messages from outgoing SMS queue ($pendingMessages queued";
  if ($GLOBALS['OUTGOING_SMS_MAX_MESSAGES']) { print ", sending max {$GLOBALS['OUTGOING_SMS_MAX_MESSAGES']} per batch"; }
  print ")\n\n";

  list($messagesSent, $sendError) = _outgoingSMS_sendQueuedMessages();
  $executeSeconds = showExecuteSeconds(true);

  if ($sendError) {
    print "\n###\n### Error Sending Message: $sendError\n###\n";
  }else{
    print "Messages sent successfully!\n";
  }

  // return summary message
  if (@$_REQUEST['_pluginAction'] == __FUNCTION__) { exit; }  // exit if being run manually from web
  return "Queued messages sent successfully.";  // otherwise, return summary if being run by cron

}


// check if user has access to send messages via "Advanced Commands..." menu
function _outgoingSMS_advancedOption_hasAccess() {
  global $CURRENT_USER, $hasEditorAccess;


  // error checking
  $accessReq = $GLOBALS['OUTGOING_SMS_SEND_ACCESS_REQ'];
  $validAccessLevels = array('admin','editor','');
  if (!in_array($accessReq, $validAccessLevels)) {
    die("Unknown value '" .htmlencode($accessReq). "' specified for \$GLOBALS['OUTGOING_SMS_SEND_ACCESS_REQ']!");
  }

  //
  if ($accessReq == 'admin' && $CURRENT_USER['isAdmin']) { return true; }
  if ($accessReq == 'editor' && $hasEditorAccess)        { return true; }

  //
  return false;
}

//
function _outgoingSMS_advancedOption_addLink($labelsToValues) {
  if (!_outgoingSMS_advancedOption_hasAccess()) { return $labelsToValues; }

  // add option
  $smsFieldExists = @$GLOBALS['schema'][ $GLOBALS['OUTGOING_SMS_PHONE_FIELD'] ];
  if ($smsFieldExists) {
    $labelsToValues['Send SMS (Search Results)']  = 'sendSMS_searchResults';
  }

  //
  return $labelsToValues;
}


// dispatch commands
function _outgoingSMS_advancedOption_dispatch($tableName, $action) {
  if (!@$_REQUEST['_advancedActionSubmit']) { return; } // skip unless "Advanced Commands" Go button clicked
  if (@$_REQUEST['_advancedAction'] != 'sendSMS_searchResults') { return; } // skip unless advanced option is selected
  if (!$tableName) { die(__FUNCTION__ . ": No 'tableName' specified!"); }

  // check access
  if (!_outgoingSMS_advancedOption_hasAccess()) { return; }

  ### set $_REQUEST['_to'] if it's not already set
  if (!array_key_exists('_to', $_REQUEST)) {

    // load records matching search query
    require_once("lib/viewer_functions.php");
    list($records,) = getRecords(array(
      'tableName'        => $tableName,
      'allowSearch'      => true,
      'loadUploads'      => false,
      'loadCreatedBy'    => false,
      'loadPseudoFields' => false,
    ));

    // get mobile numbers
    $smsNumbers = array_pluck($records, $GLOBALS['OUTGOING_SMS_PHONE_FIELD']);
    $smsNumbers = array_filter($smsNumbers); // remove blank values
    $smsNumbers = array_unique($smsNumbers); // remove duplicate values

    // error checking
    $errors = '';
    if (!$smsNumbers) { $errors .= "There are no mobile numbers in any of the records."; }
    foreach ($smsNumbers as $number) {
      if (preg_match("/[^0-9,]+/", $number)) { $errors .= "SMS number '" .htmlencode($number). "' can only contain numbers and commas (0-9,)!<br/>\n"; }
    }
    if ($errors) { die($errors); }

    //
    $_REQUEST['_to'] = implode("\n", $smsNumbers);
  }

  // send to form
  $_REQUEST['_backUrl'] = "?menu=$tableName";
  _outgoingSMS_sendForm();
  exit;
}



// this form is shown when a user clicks "Send Test SMS" from the plugin menu -OR-
// when a user selects "Send SMS (Search Results)" from the "Advanced Commands" menu
function _outgoingSMS_sendForm() {
  global $tableName, $CURRENT_USER;
  list($thisPluginPath, $thisPluginUrl) = getPluginPathAndUrl();

  ### Security check
  // "Advanced Options..." - security is checked in _outgoingSMS_advancedOption_dispatch (admin or editor based on OUTGOING_SMS_SEND_ACCESS_REQ)
  // Plugin "Send Test SMS" - admin access if required via 3rd argument of pluginAction_addHandlerAndLink()

  // get message details
  $smsNumbers = preg_split("/\s+|,/", @$_REQUEST['_to']);
  $smsNumbers = array_unique(array_filter($smsNumbers)); // remove duplicates and blanks
  $from       = @$_REQUEST['from'];
  $text       = @$_REQUEST['text'];

  // send or queue message(s)
  $smsErrors    = '';
  $smsResponses = array();
  $smsFunction  = '';
  foreach ($smsNumbers as $to) {
    // security: require POST form to send messages
    if     (@$_POST['sendAction'] == 'send')  { $smsFunction = 'outgoingSMS_sendMessage'; }
    elseif (@$_POST['sendAction'] == 'queue') { $smsFunction = 'outgoingSMS_queueMessage'; }
    if ($smsFunction) {
      list($myError, $myResponse) = call_user_func($smsFunction, $from, $to, $text);
      if ($myError)    { $smsErrors     .= $myError . "\n\n"; }
      if ($myResponse) { $smsResponses[] = $myResponse; }
    }
  }

  // show header
  $title              = 'Send SMS Messages';
  $buttons            = [[ 'name' => 'back_to_plugins', 'label' => 'Back to Plugins &gt;&gt;',  'onclick' => 'window.location="?menu=admin&action=plugins";', 'type' => 'button' ]];
  $showDefaultButton  = true;
  if (@$_REQUEST['_backUrl']) { // if _backUrl specified used that instead
    $buttons            = [[ 'name' => 'back_to_backUrl', 'label' => 'Back &gt;&gt;',  'onclick' => "window.location='" .htmlencode(@$_REQUEST['_backUrl']). "';", 'type' => 'button' ]];
    $showDefaultButton = false;
  }
  
  echo plugin_header($title, $buttons, $showDefaultButton);

  // show content
  ?>

  <?php if (@$_REQUEST['_advancedAction']): // if being called from "Advanced Commands..." ?>
    <input type="hidden" name="menu"                  value="<?php echo htmlencode(@$_REQUEST['menu']); ?>" />
    <input type="hidden" name="_advancedAction"       value="<?php echo htmlencode(@$_REQUEST['_advancedAction']); ?>" />
    <input type="hidden" name="_advancedActionSubmit" value="<?php echo htmlencode(@$_REQUEST['_advancedActionSubmit']); ?>" />
    <input type="hidden" name="_backUrl"              value="<?php echo htmlencode(@$_REQUEST['_backUrl']); ?>" />
  <?php else: // else if being called from plugin menu ?>
    <input type="hidden" name="_plugin"       value="<?php echo htmlencode($thisPluginPath); ?>" />
    <input type="hidden" name="_pluginAction" value="<?php echo __FUNCTION__ ?>" />
  <?php endif ?>
  
    <?php if($GLOBALS['OUTGOING_SMS_GATEWAY'] == 'txtlocal.com'): //The twilio phone number is set the config file ?>
      <div class="form-group">
        <div class="col-sm-1 control-label">
          From
        </div>
        <div class="col-sm-11 form-field-container">
          <div class="col-sm-4 col-xs-5">
            <input type="text" name="from" value="<?php echo htmlencode( @$_REQUEST['from']) ?>" size="20" maxlength='11' class="text-input form-control" style="width: 400px" />
          </div>
          <div class="clearfix"></div>
            <span>Mobile number starting with with the <a href="http://en.wikipedia.org/wiki/List_of_mobile_phone_codes_by_country#International_prefixes_table">international prefix</a><!-- --></span>
        </div>
      </div>
    <?php endif; ?>
    
    <div class="form-group">
      <div class="col-sm-1 control-label">
        To
      </div>
      <div class="col-sm-11 form-field-container">
        <div class="col-sm-4 col-xs-5">
          <textarea name="_to" cols="20" class="form-control" rows="10" style="width: 400px !important; height: 75px; margin-right: 5px; float: left"><?php echo implode("\n", $smsNumbers); ?></textarea>
        </div>
        <div class="clearfix"></div>
          <span>
            Mobile number starting with with the <a href="http://en.wikipedia.org/wiki/List_of_mobile_phone_codes_by_country#International_prefixes_table">international prefix</a><br/>
            You can enter multiple numbers, one per line.
          </span>
      </div>
    </div>
    
    <div class="form-group">
      <div class="col-sm-1 control-label">
        Message
      </div>
      <div class="col-sm-11 form-field-container">
        <div class="col-sm-4 col-xs-5">
          <textarea name="text" class="form-control" style="width: 400px !important; height: 75px" rows="5" cols="50"><?php echo htmlencode( @$_REQUEST['text']) ?></textarea>
        </div>
      </div>
    </div>
    
    <div class="form-group">
      <div class="col-sm-1 control-label">
        Action
      </div>
      <div class="col-sm-11 form-field-container">
        <div class="col-sm-4 col-xs-5">
          <?php
             list($runScriptPath, $runScriptUrl) = getPluginPathAndUrl('run.php');
             $_REQUEST['sendAction'] = coalesce(@$_REQUEST['sendAction'], 'send'); // set default value
           ?>
           <label><input type="radio" name="sendAction" value="send"  <?php checkedIf(@$_REQUEST['sendAction'], 'send')  ?> />Send Instantly</label><br/>
           <label><input type="radio" name="sendAction" value="queue" <?php checkedIf(@$_REQUEST['sendAction'], 'queue') ?> />Add to queue</label>:
             <a href="?menu=<?php echo $GLOBALS['OUTGOING_SMS_TABLENAME'] ?>">view queue</a>,
             <a href="<?php echo $runScriptUrl ?>?i=1">send queued messages</a>
        </div>
      </div>
    </div>
    
    <div class="form-group">
      <div class="col-sm-1 control-label">
        
      </div>
      <div class="col-sm-11 form-field-container">
        <div class="col-sm-4 col-xs-5">
          <?php echo adminUI_button(['type' => 'submit', 'btn-type' => 'default', 'label' => t('Send Messages'), 'value' => '1']); ?>
        </div>
      </div>
    </div>
    
    <div class="clearfix" style="margin-bottom: 20px"></div>

<?php if (@$_POST['sendAction']): ?>

  <?php echo adminUI_separator(t('Request')) ?>

  <table style="border-spacing: 4px; margin-bottom: 20px;">
    <tr>
      <td><b>Gateway</b></td>
      <td>&nbsp;:&nbsp;</td>
      <td><?php echo htmlencode( $GLOBALS['OUTGOING_SMS_GATEWAY'] ) ?></td>
    </tr>
    <tr>
      <td><b>From</b></td>
      <td>&nbsp;:&nbsp;</td>
      <td><?php echo htmlencode(@$_REQUEST['from']) ?></td>
    </tr>
    <tr>
      <td><b>To</b></td>
      <td>&nbsp;:&nbsp;</td>
      <td><?php echo htmlencode(implode(', ', $smsNumbers)); ?></td>
    </tr>
    <tr>
      <td><b>Text</b></td>
      <td>&nbsp;:&nbsp;</td>
      <td><?php echo nl2br(htmlencode(@$_REQUEST['text'])) ?></td>
    </tr>
  </table>

  <?php echo adminUI_separator(t('Response')) ?>

  <table style="border-spacing: 4px">
    <tr>
      <td><b>Send Errors</b></td>
      <td>&nbsp;:&nbsp;</td>
      <td><?php echo nl2br(htmlencode($smsErrors)); ?></td>
    </tr>

    <?php foreach ($smsResponses as $response): ?>
      <?php if (!$response) { continue; } ?>
      <tr><td colspan="3"><hr/></td></tr>
      <?php foreach ($response as $name => $value): ?>
        <?php if(is_string($value)): ?>
          <tr>
            <td><b><?php echo htmlencode($name); ?></b></td>
            <td>&nbsp;:&nbsp;</td>
            <td><?php echo nl2br(htmlencode($value)); ?></td>
          </tr>
        <?php endif; ?>
      <?php endforeach ?>
    <?php endforeach ?>
  </table>

<?php endif ?>

  <?php // show footer
  echo plugin_footer();
  exit;
}

//eof