SmsGateway.java :  » SMS » sms2air » de » crashsource » sms2air » smsgateway » Android Open Source

Android Open Source » SMS » sms2air 
sms2air » de » crashsource » sms2air » smsgateway » SmsGateway.java
package de.crashsource.sms2air.smsgateway;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

import android.util.Log;
import de.crashsource.sms2air.common.Common;
import de.crashsource.sms2air.common.GsmCharset;
import de.crashsource.sms2air.interfaces.ISms;
import de.crashsource.sms2air.interfaces.ISmsGateway;

/**
 * 
 * @author Fabian Mueller, .crashsource, 2010
 * 
 */
public class SmsGateway implements ISmsGateway, ISms {
  public static final String TAG = SmsGateway.class.getSimpleName();

  /**
   * This is the name of the provider.
   */
  public static final String PROVIDER_NAME = "smstrade.de";

  /**
   * This is the URL (without <code>http://</code>) for the gateway to send
   * SMS.
   */
  public static String GATEWAY = "gateway.smstrade.de";

  /**
   * These are the codes the service returns. Please note that all codes have
   * to be greater than zero!
   */
  public static int[] RETURN_CODES = new int[] { 10, 20, 30, 31, 40, 50, 60,
      70, 71, 80, 100 };

  /**
   * This code is returned if the SMS was sent successfully. Must be part of
   * <code>RETURN_CODES</code>.
   */
  public static final int RETURN_CODE_OK = 100;

  /**
   * These routes are defined for the service.
   */
  public static final String[] ROUTES = new String[] { "basic", "economy",
      "gold", "direct" };
  
  /**
   * These routes allows unicode formated sms.
   */
  public static final String[] UNICODE_ROUTES = new String[] { ROUTES[1], ROUTES[2], ROUTES[3] };

  /**
   * This is the key to identify with the smstrade.de service. Needs to be set
   * before calling {@link #send}.
   */
  private static String API_KEY = "";

  /**
   * This is the URL to the API of the smstrade service. Needs to be set on
   * the constructor.
   */
  private URL API_URL;

  private final String TO = "to";
  private final String FROM = "from";
  private final String MESSAGE = "message";
  private final String ROUTE = "route";
  private final String KEY = "key";
  private final String DEBUG = "debug";
  private final String COST = "cost";
  private final String COUNT = "count";
  private final String TIMESTAMP = "senddate";
  private final String CONCAT = "concat";
  private final String CHARSET = "charset";
  private final String DELIVERY_REPORT = "dlr";
  private final String MESSAGE_TYPE = "messagetype";

  private boolean mDebugMode = false;
  private boolean mCostRequest = true;
  private boolean mCountRequest = true;
  private boolean mAutoConcat = true;
  private String mCharset = "UTF-8";
  private boolean mDeliveryReport = false;

  private double mCost = 0.0;
  private int mCount = 0;

  public SmsGateway(String apiKey) {
    API_KEY = apiKey;

    try {
      API_URL = new URL("http", GATEWAY, 80, "");
    } catch (MalformedURLException e) {
    } // that never happens, because URL is fix
  }

  @Override
  public String getDefaultRoute() {
    return ROUTES[0];
  }

  @Override
  public void setKey(String key) {
    API_KEY = key;
  }

  @Override
  public String getKey() {
    return API_KEY;
  }

  @Override
  public void setApiUrl(URL url) {
    API_URL = url;
  }

  @Override
  public int getReturnCodeIndex(int returnCode) {
    for (int i = 0; i < RETURN_CODES.length; i++) {
      if (returnCode == RETURN_CODES[i])
        return i;
    }
    return RETURN_CODE_NOT_FOUND;
  }

  @Override
  public boolean getDebugMode() {
    return mDebugMode;
  }

  @Override
  public boolean hasDebugMode() {
    return true;
  }

  @Override
  public void setDebugMode(boolean bool) {
    mDebugMode = bool;
  }

  @Override
  public float getCreditStatus() {
    List<String> keys = new ArrayList<String>();
    List<String> values = new ArrayList<String>();

    keys.add(KEY);
    values.add(API_KEY);

    String data = "";
    try {
      data += prepareDataForRequest(keys, values);
    } catch (UnsupportedEncodingException e) {
      Log.e(TAG, "getCreditStatus(): The data could not be encoded.");
    }
    Log.v(TAG, "getCreditStatus(): data: " + data);

    String retTemp = "";
    HttpClient httpclient = new DefaultHttpClient();
    HttpGet httpget = new HttpGet("http://" + GATEWAY + "/credits/?" + data);
    Log.v(TAG, "getCreditStatus(): executing request " + httpget.getURI());

    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    try {
      retTemp = httpclient.execute(httpget, responseHandler);
    } catch (Exception e) {
      Log.e(TAG, "getCreditStatus(): could not get response. Error: "
          + e.getMessage());
    }

    float ret = Float.parseFloat(retTemp);
    return ret;
  }

  @Override
  public String[] getRoutes() {
    return ROUTES;
  }

  @Override
  public String[] getRoutesWithCustomSenderAddress() {
    return new String[] { ROUTES[1], ROUTES[2], ROUTES[3] };
  }

  @Override
  public boolean hasCreditStatus() {
    return true;
  }

  @Override
  public int send(String route, String to, String from, String message,
      long timestamp) throws IllegalArgumentException {

    if (route == null || route.length() == 0)
      throw new IllegalArgumentException("There must be a route!");
    if (to == null)
      throw new IllegalArgumentException("There must be a recipient!");

    int retCode = 0;

    // reset values
    mCost = 0;
    mCount = 0;

    // filter the phone number
    to = Common.preparePhoneNumber(to);

    // remove sender address if route doesn't allow it
    if (!isCustomSenderAddressAllowedForRoute(route)) {
      from = "";
    }

    // what to do if sms is more than 160 words long?
    int concat = 0;
    if (message.length() > SMS_LENGTH_SINGLE && mAutoConcat) {
      concat = 1;
    }

    List<String> keys = new ArrayList<String>();
    List<String> values = new ArrayList<String>();

    keys.add(KEY);
    values.add(API_KEY);

    keys.add(ROUTE);
    values.add(route);

    keys.add(TO);
    values.add(to);

    keys.add(FROM);
    values.add(from == null ? "" : from);

    keys.add(MESSAGE);
    values.add(message);

    keys.add(TIMESTAMP);
    values.add(Long.toString(timestamp));

    keys.add(COST);
    values.add(mCostRequest ? "1" : "0");

    keys.add(COUNT);
    values.add(mCountRequest ? "1" : "0");

    keys.add(CONCAT);
    values.add(Integer.toString(concat));

    keys.add(DEBUG);
    values.add(mDebugMode ? "1" : "0");

    keys.add(CHARSET);
    values.add(mCharset);

    keys.add(DELIVERY_REPORT);
    values.add(mDeliveryReport ? "1" : "0");

    // String[] keys = new String[] { KEY, ROUTE, TO, FROM, MESSAGE,
    // TIMESTAMP, COST, COUNT, CONCAT, DEBUG, CHARSET, DELIVERY_REPORT };
    // String[] values = new String[] { API_KEY, route, to, from, message,
    // Long.toString(timestamp), mCostRequest ? "1" : "0",
    // mCountRequest ? "1" : "0", Integer.toString(concat),
    // mDebugMode ? "1" : "0", mCharset, mDeliveryReport ? "1" : "0" };

    /*
     * Check if the message have to be a unicode message.
     */
    GsmCharset gc = new GsmCharset();
    if (!gc.isEncodeableInGsm0338(message)) {
      keys.add(MESSAGE_TYPE);
      values.add("unicode");
    }

    String data = "";
    try {
      data = prepareDataForRequest(keys, values);
    } catch (UnsupportedEncodingException e) {
      retCode = RETURN_CODE_INTERNAL_ERROR;
      Log.e(TAG, "send(): The data could not be encoded. Err-Msg: "
          + e.getMessage());
    }

    Log.v(TAG, "send(): data: " + data);

    try {
      // Send data
      URLConnection conn = API_URL.openConnection();
      conn.setDoOutput(true);
      OutputStreamWriter wr = new OutputStreamWriter(conn
          .getOutputStream());
      wr.write(data);
      wr.flush();

      // Get the response
      BufferedReader rd = new BufferedReader(new InputStreamReader(conn
          .getInputStream()));
      String line;
      int i = 0;
      while ((line = rd.readLine()) != null) {
        Log.v(TAG, "send(): response line: " + line);
        if (i == 0) {
          /*
           * Normally the first line contains the response code but if
           * the SMS will be sent delayed, there will be something in
           * the form: "send at 1284209340" so we try to parse the
           * answer, but catch an error if there is one.
           * 
           * 09/11/2010: This case is not officially documented by the
           * provider yet.
           */
          try {
            retCode = Integer.parseInt(line);
          } catch (NumberFormatException e) {
            Log
                .v(TAG,
                    "send(): response - entered first line exception case");
            if (line.startsWith("send at")) {
              retCode = RETURN_CODE_OK;
            } else {
              retCode = RETURN_CODE_INTERNAL_ERROR;
            }
          }
        }
        if (i == 2)
          mCost = Double.parseDouble(line); // costs
        if (i == 3)
          mCount = Integer.parseInt(line); // count
        i++;
      }
      wr.close();
      rd.close();
    } catch (IOException e) {
      retCode = RETURN_CODE_INTERNAL_ERROR;
      Log.e(TAG, "send(): The data could not be sent. Err-Msg: "
          + e.getMessage());
    }

    Log.v(TAG, "send(): return code: " + retCode);
    return retCode;

  }

  public boolean isCustomSenderAddressAllowedForRoute(String route) {
    for (String routeAllowed : getRoutesWithCustomSenderAddress()) {
      if (route.equals(routeAllowed))
        return true;
    }
    return false;
  }

  private String prepareDataForRequest(List<String> keys, List<String> values)
      throws UnsupportedEncodingException {
    String data = "";
    GsmCharset gc = new GsmCharset();
    
    for (int i=0; i<keys.size(); i++) {
      if (!(data.length() == 0)) {
        data += "&";
      }
      
      if (values.get(i) == null) {
        values.set(i, "");
      }
      
      /*
       * If the message must be sent as a unicode message, we have to prepare the message.
       */
      if (keys.get(i).equals(MESSAGE) && !gc.isEncodeableInGsm0338(values.get(i))) {
        values.set(i, Common.stringToUtf16ByteString(values.get(i)));
      }
      
      data += URLEncoder.encode(keys.get(i), "UTF-8") + "="
        + URLEncoder.encode(values.get(i), "UTF-8");
    }
    
    return data;
  }

  private int countSms(int textlength, int maxLengthSingle, int maxLengthMulti) {
    int smsCounter = 0;
    if (textlength <= maxLengthSingle) {
      smsCounter = 1;
    } else {
      smsCounter = textlength / maxLengthMulti + 1;
      if (textlength % maxLengthMulti == 0)
        smsCounter--;
    }
    return smsCounter;
  }

  public int countSms(String text) {
    GsmCharset gc = new GsmCharset();
    if (gc.isEncodeableInGsm0338(text)) {
      int textlength = gc.count(text);
      return countSms(textlength, ISms.SMS_LENGTH_SINGLE,
          ISms.SMS_LENGTH_MUTLI);
    } else {
      return countSms(text.length(), 70, 70);
    }
  }

  public int countChars(String text) {
    GsmCharset gc = new GsmCharset();
    if (gc.isEncodeableInGsm0338(text)) {
      return gc.count(text);
    } else {
      return text.length();
    }
  }

  public ISms setCostRequest(boolean bool) {
    this.mCostRequest = bool;
    return this;
  }

  public ISms setCountRequest(boolean bool) {
    this.mCountRequest = bool;
    return this;
  }

  public ISms setAutoConcat(boolean bool) {
    this.mAutoConcat = bool;
    return this;
  }

  public double getCost() {
    return mCost;
  }

  public double getCount() {
    return mCount;
  }

  @Override
  public boolean hasDeliveryReport() {
    return true;
  }

  @Override
  public void setDeliveryReport(boolean bool) {
    mDeliveryReport = bool;
  }
  
  public boolean routeAllowsUnicodeText(String route) {
    for (String unicodeRoute : UNICODE_ROUTES) {
      if (unicodeRoute.equals(route)) {
        return true;
      }
    }
    return false;
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.