@Override
  protected void onHandleIntent(Intent intent) {
    Log.d(TAG, "Started DataSmsReceivedService");
    ThreeHeadedMonkeyApplication application = (ThreeHeadedMonkeyApplication) getApplication();
    Bundle bundle = intent.getExtras();
    if (bundle == null) return;
    Object[] pdus = (Object[]) bundle.get("pdus");
    if (pdus == null || pdus.length == 0) return;

    for (int i = 0; i < pdus.length; i++) {
      try {
        SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
        //                Log.d(TAG, "Received PDU: " + new String(Hex.encodeHex((byte[])
        // pdus[i])));
        byte[] data = smsMessage.getUserData();
        String message = new String(data, "UTF-8");
        String sender = smsMessage.getOriginatingAddress();
        Log.d(TAG, "Received data-sms from " + sender + ": " + message);

        List<PhoneNumberInfo> infos = application.phoneNumberSettings.findEntriesForNumber(sender);
        if (infos.isEmpty()) {
          Log.d(TAG, "Datasms sender not authorized to send commands");
          continue;
        }

        Intent command_intent = new Intent(this, CommandExecutorService.class);
        command_intent.putExtra(CommandExecutorService.INTENT_COMMAND_STRING_PARAM, message);
        command_intent.putExtra(
            CommandExecutorService.INTENT_OUTGOING_COMMUNICATION_TYPE_PARAM,
            OutgoingCommandCommunicationFactory.OUTGOING_COMMUNICATION_TYPE_DATASMS);
        command_intent.putExtra(
            CommandExecutorService.INTENT_OUTGOING_COMMUNICATION_SENDER_ADDRESS_PARAM, sender);

        startService(command_intent);
      } catch (Exception ex) {
        Log.e(TAG, "Exception while parsing data sms", ex);
      }
    }
  }
  /**
   * Creates and returns a Message object from the provided PDU if possible
   *
   * @param pdu the message PDU (protocol data unit - header and payload) as a byte array
   * @return a BinaryMessage or TextMessage object depending on the type of the message provided
   * @throws InvalidMessageException if the message was definitely not relevant to Sapelli
   * @throws Exception for any other errors that occur while trying to parse the message
   */
  private Message<?, ?> messageFromPDU(byte[] pdu, boolean binary)
      throws InvalidMessageException, Exception {
    // Get Android SMS msg representation for pdu:
    SmsMessage androidMsg = SmsMessage.createFromPdu(pdu);
    if (androidMsg == null)
      throw new Exception("Android could not parse the SMS message from its PDU.");

    // Debug:
    // Log.d(TAG,"MESSAGE BODY: " + androidMsg.getMessageBody());

    // Get sender phone number (we assume that if the number doesn't start with '+' the correct
    // country is given by the current network (rather than the SIM)):
    PhoneNumber senderPhoneNumber =
        SMSCorrespondent.toPhoneNumber(
            androidMsg.getOriginatingAddress(), DeviceControl.getNetworkCountryISOCode(this));
    // Get an SMSCorrespondent corresponding to this phone number:
    SMSCorrespondent sender =
        transmissionController.getSendingCorrespondentFor(senderPhoneNumber, binary);

    // Return Sapelli Message:
    if (binary) return new BinaryMessage(sender, androidMsg.getUserData());
    else return new TextMessage(sender, androidMsg.getMessageBody());
  }
  /** {@inheritDoc} */
  protected int dispatchMessage(SmsMessageBase smsb) {

    // If sms is null, means there was a parsing error.
    if (smsb == null) {
      return Intents.RESULT_SMS_GENERIC_ERROR;
    }
    SmsMessage sms = (SmsMessage) smsb;
    boolean handled = false;

    if (sms.isTypeZero()) {
      // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
      // Displayed/Stored/Notified. They should only be acknowledged.
      Log.d(TAG, "Received short message type 0, Don't display or store it. Send Ack");
      return Intents.RESULT_SMS_HANDLED;
    }

    // Special case the message waiting indicator messages
    if (sms.isMWISetMessage()) {
      mGsmPhone.updateMessageWaitingIndicator(true);
      handled = sms.isMwiDontStore();
      if (Config.LOGD) {
        Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
      }
    } else if (sms.isMWIClearMessage()) {
      mGsmPhone.updateMessageWaitingIndicator(false);
      handled = sms.isMwiDontStore();
      if (Config.LOGD) {
        Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
      }
    }

    if (handled) {
      return Intents.RESULT_SMS_HANDLED;
    }

    if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) {
      // It's a storable message and there's no storage available.  Bail.
      // (See TS 23.038 for a description of class 0 messages.)
      return Intents.RESULT_SMS_OUT_OF_MEMORY;
    }

    SmsHeader smsHeader = sms.getUserDataHeader();
    // See if message is partial or port addressed.
    if ((smsHeader == null) || (smsHeader.concatRef == null)) {
      // Message is not partial (not part of concatenated sequence).
      byte[][] pdus = new byte[1][];
      pdus[0] = sms.getPdu();

      if (smsHeader != null && smsHeader.portAddrs != null) {
        if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
          return mWapPush.dispatchWapPdu(sms.getUserData());
        } else {
          // The message was sent to a port, so concoct a URI for it.
          dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
        }
      } else {
        // Normal short and non-port-addressed message, dispatch it.
        dispatchPdus(pdus);
      }
      return Activity.RESULT_OK;
    } else {
      // Process the message part.
      return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
    }
  }