com.rothconsulting.android.websms.connector.schoolnet.ConnectorSchoolnet.java Source code

Java tutorial

Introduction

Here is the source code for com.rothconsulting.android.websms.connector.schoolnet.ConnectorSchoolnet.java

Source

/*
 * Copyright (C) 2010 Koni
 * 
 * This file is only usefull as part of WebSMS.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; If not, see <http://www.gnu.org/licenses/>.
 */
package com.rothconsulting.android.websms.connector.schoolnet;

import java.net.HttpURLConnection;
import java.util.ArrayList;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

import com.google.analytics.tracking.android.GoogleAnalytics;
import com.google.analytics.tracking.android.Tracker;

import de.ub0r.android.websms.connector.common.Connector;
import de.ub0r.android.websms.connector.common.ConnectorCommand;
import de.ub0r.android.websms.connector.common.ConnectorSpec;
import de.ub0r.android.websms.connector.common.ConnectorSpec.SubConnectorSpec;
import de.ub0r.android.websms.connector.common.Log;
import de.ub0r.android.websms.connector.common.Utils;
import de.ub0r.android.websms.connector.common.Utils.HttpOptions;
import de.ub0r.android.websms.connector.common.WebSMSException;

/**
 * AsyncTask to manage IO to Schoolnet API.
 * 
 * @author koni
 */
public class ConnectorSchoolnet extends Connector {
    /** Tag for output. */
    private static final String TAG = "Schoolnet";
    /** Dummy String */
    private static final String DUMMY = "???";
    /** Homepage URL. */
    private static final String URL_LOGIN_PAGE = "http://www.schoolnet.ch/DE/HomeDE.htm";
    /** Login URL. */
    private static final String URL_LOGIN_ACTION = "http://www.schoolnet.ch/schoolnet/Templates/HomePage.aspx?NRMODE=Published&NRNODEGUID=%7bFC1600E3-5CFE-4E47-A279-A0917FF86261%7d&NRORIGINALURL=%2fDE%2fHomeDE%2ehtm&NRCACHEHINT=NoModifyGuest";
    /** SMS send action URL. */
    private static final String URL_SEND_PAGE = "http://www.schoolnet.ch/DE/FreundeInternet/SMS/";
    /** SMS send action URL. */
    private static final String URL_SEND_ACTION = "http://www.schoolnet.ch/schoolnet/Templates/Template5Slots.aspx?NRMODE=Published&NRNODEGUID=%7bE1B58CDA-3DA6-45D3-9F95-F8E078143033%7d&NRORIGINALURL=%2fDE%2fFreundeInternet%2fSMS%2f&NRCACHEHINT=NoModifyLoggedIn";

    /** SMS Credit */
    private String SMS_CREDIT = DUMMY;
    /** HTTP User agent. */
    private static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:31.0) Gecko/20100101 Firefox/31.0";
    /** SMS Encoding */
    private static final String ENCODING = "UTF-8";
    /** Check whether this connector is bootstrapping. */
    private static boolean inBootstrap = false;
    /** Only when mobile number is entered, check for sender errors. */
    private static boolean checkForSenderErrors = false;
    /** My Ad-ID */
    private static final String AD_UNITID = "ca-app-pub-5619114666968507/9953800139";
    /** My Analytics-ID */
    private static final String ANALYTICS_ID = "UA-38114228-3";

    private Tracker mGaTracker;
    private GoogleAnalytics mGaInstance;

    /**    */
    private String VIEWSTATE_LOGIN = "VIEWSTATE_LOGIN";
    /**    */
    private String VIEWSTATE_SEND = "VIEWSTATE_SEND";

    private void initAnalytics(final Context context) {
        // Get singleton.
        this.mGaInstance = GoogleAnalytics.getInstance(context);
        // To set the default tracker, use:
        // First get a tracker using a new property ID.
        Tracker newTracker = this.mGaInstance.getTracker(ANALYTICS_ID);
        // Then make newTracker the default tracker globally.
        this.mGaInstance.setDefaultTracker(newTracker);
        // Get default tracker.
        this.mGaTracker = this.mGaInstance.getDefaultTracker();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final ConnectorSpec initSpec(final Context context) {
        final String name = context.getString(R.string.connector_schoolnet_name);
        ConnectorSpec c = new ConnectorSpec(name);
        c.setAuthor(context.getString(R.string.connector_schoolnet_author));
        c.setBalance(null);
        c.setAdUnitId(AD_UNITID);
        c.setCapabilities(ConnectorSpec.CAPABILITIES_BOOTSTRAP | ConnectorSpec.CAPABILITIES_UPDATE
                | ConnectorSpec.CAPABILITIES_SEND | ConnectorSpec.CAPABILITIES_PREFS);
        c.addSubConnector("schoolnet", c.getName(), SubConnectorSpec.FEATURE_MULTIRECIPIENTS);
        return c;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final ConnectorSpec updateSpec(final Context context, final ConnectorSpec connectorSpec) {
        this.log("Start updateSpec");
        final SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(context);
        if (p.getBoolean(Preferences.PREFS_ENABLED, false)) {
            if (p.getString(Preferences.PREFS_USER, "").length() > 0 && p.getString(Preferences.PREFS_PASSWORD, "") // .
                    .length() > 0) {
                connectorSpec.setReady();
            } else {
                connectorSpec.setStatus(ConnectorSpec.STATUS_ENABLED);
            }
        } else {
            connectorSpec.setStatus(ConnectorSpec.STATUS_INACTIVE);
        }
        this.log("End updateSpec");
        return connectorSpec;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected final void doBootstrap(final Context context, final Intent intent) throws WebSMSException {
        this.log("Start doBootstrap");
        checkForSenderErrors = false;

        if (inBootstrap && !this.SMS_CREDIT.equals(DUMMY)) {
            this.log("already in bootstrap: skip bootstrap");
            return;
        }

        // get schoolnet view state
        this.sendData(URL_LOGIN_PAGE, context, null, false);

        inBootstrap = true;
        final SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(context);

        ArrayList<BasicNameValuePair> postParameter = new ArrayList<BasicNameValuePair>();
        postParameter.add(new BasicNameValuePair("BotM:ucUser:ucUser2Col:txtUsername",
                p.getString(Preferences.PREFS_USER, "")));
        postParameter.add(new BasicNameValuePair("BotM:ucUser:ucUser2Col:txtPassword",
                p.getString(Preferences.PREFS_PASSWORD, "")));
        postParameter.add(new BasicNameValuePair("__EVENTTARGET", "BotM:ucUser:ucUser2Col:cmdLogin"));
        postParameter.add(new BasicNameValuePair("__EVENTARGUMENT", ""));

        postParameter.add(new BasicNameValuePair("__VIEWSTATE", this.VIEWSTATE_LOGIN));

        ArrayList<Header> headers = new ArrayList<Header>();
        headers.add(new BasicHeader("Referer", URL_LOGIN_PAGE));

        this.sendData(URL_LOGIN_ACTION, context, postParameter, true);
        this.log("End doBootstrap");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected final void doUpdate(final Context context, final Intent intent) throws WebSMSException {
        this.log("Start doUpdate");
        this.doBootstrap(context, intent);

        this.initAnalytics(context);

        // ArrayList<Header> headers = new ArrayList<Header>();
        // headers.add(new BasicHeader("Referer", URL_LOGIN_PAGE));

        this.sendData(URL_SEND_PAGE, context, null, true);
        this.getSpec(context).setBalance(this.SMS_CREDIT);

        // Google analytics
        if (this.mGaTracker != null) {
            this.log("Tracking ID=" + this.mGaTracker.getTrackingId());
            this.mGaTracker.sendEvent(TAG, "doUpdate", "Balance: " + this.getSpec(context).getBalance(), 0L);
        }

        this.log("End doUpdate");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected final void doSend(final Context context, final Intent intent) throws WebSMSException {
        this.log("Start doSend");
        this.doBootstrap(context, intent);

        ConnectorCommand command = new ConnectorCommand(intent);

        // SMS Text
        String text = command.getText();
        this.log("text.length()=" + text.length());
        this.log("text=" + text);

        // SMS Recipients
        String[] to = command.getRecipients();
        String prefix = "";
        String number = "";
        if (to == null || to.length > 10) {
            String error = context.getString(R.string.connector_schoolnet_max_10_recipients);
            this.log("----- throwing WebSMSException: " + error);
            throw new WebSMSException(error);
        }

        // get schoolnet view state
        this.sendData(URL_SEND_PAGE, context, null, false);

        for (int i = 0; i < to.length; i++) {
            if (to[i] != null && to[i].length() > 1) {

                // Building POST parameter
                ArrayList<BasicNameValuePair> postParameter = new ArrayList<BasicNameValuePair>();
                postParameter.add(new BasicNameValuePair("__EVENTTARGET",
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:cmdAnswer"));
                postParameter.add(new BasicNameValuePair("__EVENTARGUMENT", ""));
                postParameter.add(new BasicNameValuePair("__VIEWSTATE", this.VIEWSTATE_SEND));
                postParameter.add(new BasicNameValuePair(
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:txt_PhonePrefix", ""));
                postParameter.add(new BasicNameValuePair(
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:txt_Phone", "rbSendNumber"));

                postParameter.add(new BasicNameValuePair(
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:txt_Message", text));

                String fullNumber = Utils.getRecipientsNumber(to[i]);

                this.log("--- anzahl=" + to.length);
                this.log("--- to[" + i + "]=" + to[i]);
                this.log("--- fullNumber=" + fullNumber);

                if (fullNumber.startsWith("+417")) {
                    prefix = fullNumber.substring(0, 5);
                    number = fullNumber.substring(5, 12);
                    this.log("--- prefix=" + prefix);
                    this.log("--- number=" + number);
                }
                if (fullNumber.startsWith("00417")) {
                    prefix = fullNumber.substring(0, 6);
                    number = fullNumber.substring(6, 13);
                    this.log("--- prefix=" + prefix);
                    this.log("--- number=" + number);
                }
                if (fullNumber.startsWith("07")) {
                    prefix = fullNumber.substring(0, 3);
                    number = fullNumber.substring(3, 10);
                    this.log("--- prefix=" + prefix);
                    this.log("--- number=" + number);
                }

                postParameter.add(new BasicNameValuePair(
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:txtSmsListPrefix", prefix));
                postParameter.add(new BasicNameValuePair(
                        "Layout1:PresentationModeControlsContainer:_ctl2:_ctl0:_ctl0:txtSmsListHandy", number));

                ArrayList<Header> headers = new ArrayList<Header>();
                headers.add(new BasicHeader("Referer", URL_SEND_PAGE));

                // Google analytics
                if (this.mGaTracker == null) {
                    this.initAnalytics(context);
                }
                if (this.mGaTracker != null) {
                    this.log("Tracking ID=" + this.mGaTracker.getTrackingId());
                    this.mGaTracker.sendEvent(TAG, "Send SMS", "Count receiver: " + i + 1, 0L);
                }

                // push data
                this.sendData(URL_SEND_ACTION, context, postParameter, true);
                this.log("End doSend: " + i);
            }
        }
    }

    /**
     * Sending the request (Login or SMS)
     * 
     * @param url
     * @param context
     * @param postParameter
     * @param parseHtml
     * @throws WebSMSException
     */
    private void sendData(final String url, final Context context,
            final ArrayList<BasicNameValuePair> postParameter, final boolean parseHtml) throws WebSMSException {
        this.log("Start sendData");
        try {

            this.log("URL: " + url);
            // send data

            HttpOptions httpOptions = new HttpOptions();
            httpOptions.url = url;
            httpOptions.userAgent = USER_AGENT;
            // httpOptions.trustAll = true;
            if (postParameter != null) {
                this.log("UrlEncodedFormEntity(postParameter,ENCODING)");
                httpOptions.postData = new UrlEncodedFormEntity(postParameter, ENCODING);
            }
            this.log("send data: getHttpClient(...)");
            HttpResponse response = Utils.getHttpClient(httpOptions);

            int respStatus = response.getStatusLine().getStatusCode();
            this.log("response status    =" + respStatus);
            this.log("response statusLine=" + response.getStatusLine());
            if (respStatus != HttpURLConnection.HTTP_OK) {
                this.log("response headers  =\n" + ConnectorSchoolnet.getHeaders(response.getAllHeaders()));

                throw new WebSMSException(context, R.string.error_http, "" + respStatus);
            }
            String htmlText = Utils.stream2str(response.getEntity().getContent()).trim();
            if (htmlText == null || htmlText.length() == 0) {
                throw new WebSMSException(context, R.string.error_service);
            }
            this.log("----- Start HTTP RESPONSE--");
            this.log(htmlText);
            this.log("----- End HTTP RESPONSE--");

            this.getSchoolnetViewstate(htmlText, url);

            if (parseHtml) {
                // this.getPhoneNumber(htmlText, context);
                String guthabenGratis = this.getGuthabenGratis(htmlText, context);
                String errorMessage = this.getErrorBlockMessage(htmlText, context);

                if (guthabenGratis != null && !guthabenGratis.equals("")) {
                    this.SMS_CREDIT = "SMS=" + guthabenGratis;
                }
                if (errorMessage != null && !errorMessage.equals("")) {
                    this.log("----- throwing WebSMSException: " + errorMessage);
                    throw new WebSMSException(errorMessage);
                }

                this.getSpec(context).setBalance(this.SMS_CREDIT);
            }

            htmlText = null;

        } catch (Exception e) {
            Log.e(TAG, null, e);
            throw new WebSMSException(e.getMessage());
        }
    }

    private String getGuthabenGratis(final String htmlText, final Context context) {
        String guthabenGratis = "";
        int indexStartSMSCredit = htmlText.indexOf("userSnPoints");
        if (indexStartSMSCredit > 0) {
            guthabenGratis = htmlText.substring(indexStartSMSCredit + 17, indexStartSMSCredit + 21);
            guthabenGratis = guthabenGratis.replace("<", "");
            guthabenGratis = guthabenGratis.replace("/", "");
            guthabenGratis = guthabenGratis.replace("b", "");
        }
        this.log("indexOf Gratis=" + indexStartSMSCredit + " -- Gratis=" + guthabenGratis);

        return guthabenGratis.trim();
    }

    private String getErrorBlockMessage(final String htmlText, final Context context) {
        String message = "";
        if (checkForSenderErrors) {
            int indexStartErrorBlock = htmlText.indexOf("errorBlock");
            int indexEndeErrorBlock = htmlText.indexOf("Die SMS/MMS wurde nicht versandt");

            if (indexStartErrorBlock > 0 && indexEndeErrorBlock > 0) {
                message = htmlText.substring(indexStartErrorBlock + 28, indexEndeErrorBlock);
            }
            this.log("indexStartOf errorBlock =" + indexStartErrorBlock + ", indexEndeOf errorBlock ="
                    + indexEndeErrorBlock + " -- Message=" + message);

            if (message.trim().startsWith("Die Absendernummer hat sich gendert")) {
                message = context.getString(R.string.connector_schoolnet_wrong_mobilenumber);
            } else {
                message = "";
            }
        }
        return message.trim();
    }

    private void getSchoolnetViewstate(final String htmlText, final String url) {

        int tokenLength = 40000;

        if (url.equals(URL_LOGIN_PAGE) || url.equals(URL_SEND_PAGE)) {

            String viewstateTmp = "";
            int indexStart = htmlText.indexOf("__VIEWSTATE\" value=\"");

            if (htmlText.length() < tokenLength) {
                tokenLength = htmlText.length() - indexStart - 1;
            }

            this.log("indexStart= " + indexStart);
            this.log("htmlText.length= " + htmlText.length());
            if (indexStart > 0) {

                viewstateTmp = htmlText.substring(indexStart + 20, indexStart + tokenLength);
                this.log("\n\n\n");
                this.log("\n\n\nviewstateTmp = " + viewstateTmp);
                this.log("tokenLength = " + tokenLength);
                this.log("\n\n\n");

                int indexEnd = viewstateTmp.indexOf("\" />");
                this.log("\nindexEnd  = " + indexEnd);

                if (indexEnd < 0) {
                    return;
                }

                viewstateTmp = viewstateTmp.substring(0, indexEnd);

                this.log("\n***--- Length=" + viewstateTmp.length() + "\nViewstate-Ende-20="
                        + viewstateTmp.substring(viewstateTmp.length() - 20));

                viewstateTmp = viewstateTmp.replace("<", "");
                viewstateTmp = viewstateTmp.replace(">", "");
                viewstateTmp = viewstateTmp.replace(" ", "");

                this.log("--- Viewstate:\nindexOfStart=" + indexStart);

                if (url.equals(URL_LOGIN_PAGE)) {
                    this.VIEWSTATE_LOGIN = viewstateTmp;
                    this.log("--- \nVIEWSTATE_LOGIN = " + this.VIEWSTATE_LOGIN);
                }
                if (url.equals(URL_SEND_PAGE)) {
                    this.VIEWSTATE_SEND = viewstateTmp;
                    this.log("--- \nVIEWSTATE_SEND = " + this.VIEWSTATE_SEND);
                }
            }
        } else {
            this.log("no viewstate needed");
            return;
        }

    }

    private static String getHeaders(final Header[] headers) {
        String ret = "\n------------\nheaders=\n";
        for (Header h : headers) {
            ret += "\n *** " + h.getName() + ": " + h.getValue();
        }
        ret += "\nend of headers\n------------\n";
        return ret;
    }

    /**
     * central logger
     * 
     * @param message
     */
    private void log(final String message) {
        // Log.d(TAG, message);
    }

}