package ryan.org.wordpress.android;
import org.apache.http.conn.HttpHostConnectException;
import ryan.org.wordpress.android.R;
import org.xmlpull.v1.XmlPullParser;
import ryan.org.wordpress.android.util.EscapeUtils;
import ryan.org.xmlrpc.android.XMLRPCClient;
import ryan.org.xmlrpc.android.XMLRPCException;
import ryan.org.xmlrpc.android.XMLRPCFault;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
public class AddAccount extends Activity {
private XMLRPCClient client;
public boolean success = false;
public String blogURL, xmlrpcURL;
public ProgressDialog pd;
private String httpuser = "";
private String httppassword = "";
private boolean wpcom = false;
private int blogCtr = 0;
public ArrayList<CharSequence> aBlogNames = new ArrayList<CharSequence>();
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.add_account);
this.setTitle("WordPress - " + getResources().getText(R.string.add_account));
Bundle extras = getIntent().getExtras();
if(extras !=null)
{
wpcom = extras.getBoolean("wpcom", false);
}
if (wpcom){
TextView urlLabel = (TextView) findViewById(R.id.l_url);
urlLabel.setVisibility(View.GONE);
EditText urlET = (EditText) findViewById(R.id.url);
urlET.setVisibility(View.GONE);
}
else {
ImageView logo = (ImageView) findViewById(R.id.wpcomLogo);
logo.setImageDrawable(getResources().getDrawable(R.drawable.wplogo));
}
final Button settingsButton = (Button) findViewById(R.id.settingsButton);
if (!wpcom) {
settingsButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Intent settings = new Intent(AddAccount.this, AddAcountSettings.class);
settings.putExtra("httpuser", httpuser);
settings.putExtra("httppassword", httppassword);
startActivityForResult(settings, R.id.settingsButton);
}
});
}
else {
settingsButton.setVisibility(View.GONE);
}
final Button cancelButton = (Button) findViewById(R.id.cancel);
final Button saveButton = (Button) findViewById(R.id.save);
saveButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
pd = ProgressDialog.show(AddAccount.this, getResources().getText(R.string.account_setup), getResources().getText(R.string.attempting_configure), true, false);
Thread action = new Thread()
{
public void run()
{
Looper.prepare();
configureAccount();
Looper.loop();
}
};
action.start();
}
});
cancelButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString("returnStatus", "CANCEL");
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
});
Button signUp = (Button) findViewById(R.id.wordpressdotcom);
signUp.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
//Intent signupIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://wordpress.com/signup/?ref=wp-android"));
Intent signupIntent = new Intent(AddAccount.this, Signup.class);
startActivity(signupIntent);
}
});
}
protected void configureAccount() {
//capture the entered fields *needs validation*
EditText urlET = (EditText)findViewById(R.id.url);
if (wpcom){
blogURL = "http://wordpress.com";
}
else {
blogURL = urlET.getText().toString().trim();
}
EditText usernameET = (EditText)findViewById(R.id.username);
final String username = usernameET.getText().toString().trim();
EditText passwordET = (EditText)findViewById(R.id.password);
final String password = passwordET.getText().toString().trim();
boolean invalidURL = false;
try {
URI.create(blogURL);
} catch (Exception e1) {
invalidURL = true;
}
if (blogURL.equals("") || username.equals("") || password.equals("")){
pd.dismiss();
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle(getResources().getText(R.string.required_fields));
dialogBuilder.setMessage(getResources().getText(R.string.url_username_password_required));
dialogBuilder.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
else if (invalidURL){
pd.dismiss();
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle(getResources().getText(R.string.invalid_url));
dialogBuilder.setMessage(getResources().getText(R.string.invalid_url_message));
dialogBuilder.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
else{
//add http or http to the beginning of the URL if needed
if (!(blogURL.toLowerCase().contains("http://")) && !(blogURL.toLowerCase().contains("https://"))){
blogURL = "http://" + blogURL; //default to http
}
String fBlogURL = "";
//attempt to get the XMLRPC URL via RSD
String rsdUrl = getRSDMetaTagHref(blogURL);
if (rsdUrl != null){
xmlrpcURL = getXMLRPCUrl(rsdUrl);
}
if (xmlrpcURL != null){
//got the xmlrpc path ok!
fBlogURL = xmlrpcURL;
}
else{
//let's try to guess, and if it doesn't work prompt the user to type in the path manually after the call.
String lastChar = blogURL.substring(blogURL.length() - 1, blogURL.length());
if (lastChar.equals("/")){
blogURL = blogURL.substring(0, blogURL.length() - 1);
}
fBlogURL = blogURL + "/xmlrpc.php";
}
//verify settings
client = new XMLRPCClient(fBlogURL, httpuser, httppassword);
XMLRPCMethod method = new XMLRPCMethod("wp.getUsersBlogs", new XMLRPCMethodCallback() {
@SuppressWarnings("unchecked")
public void callFinished(Object[] result) {
final String[] blogNames = new String[result.length];
final String[] urls = new String[result.length];
final int[] blogIds = new int[result.length];
final boolean[] wpcoms = new boolean[result.length];
final String[] wpVersions = new String[result.length];
HashMap<Object, Object> contentHash = new HashMap<Object, Object>();
WordPressDB settingsDB = new WordPressDB(AddAccount.this);
//loop this!
for (int ctr = 0; ctr< result.length; ctr++){
contentHash = (HashMap<Object, Object>) result[ctr];
//check if this blog is already set up
boolean match = false;
String matchBlogName = contentHash.get("blogName").toString();
if (matchBlogName.length() == 0){
matchBlogName = "(No Blog Title)";
}
match = settingsDB.checkMatch(AddAccount.this, matchBlogName, contentHash.get("xmlrpc").toString(), username);
if (!match){
blogNames[blogCtr] = matchBlogName;
urls[blogCtr] = contentHash.get("xmlrpc").toString();
blogIds[blogCtr] = Integer.parseInt(contentHash.get("blogid").toString());
String blogURL = urls[blogCtr];
aBlogNames.add(EscapeUtils.unescapeHtml(blogNames[blogCtr]));
boolean wpcomFlag = false;
//check for wordpress.com
if (blogURL.toLowerCase().contains("wordpress.com")){
wpcomFlag = true;
}
wpcoms[blogCtr] = wpcomFlag;
//attempt to get the software version
String wpVersion = "";
if (!wpcomFlag){
HashMap hPost = new HashMap();
hPost.put("software_version", "software_version");
Object[] vParams = {
1,
username,
password,
hPost
};
Object versionResult = new Object();
try {
versionResult = (Object) client.call("wp.getOptions", vParams);
} catch (XMLRPCException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
if (versionResult != null){
try {
contentHash = (HashMap) versionResult;
HashMap sv = (HashMap) contentHash.get("software_version");
wpVersion = sv.get("value").toString();
} catch (Exception e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
}
else{
wpVersion = "3.0"; //wpcom is v3.0
}
wpVersions[blogCtr] = wpVersion;
blogCtr++;
//success = settingsDB.addAccount(addAccount.this, blogURL, blogName, username, password, "Above Text", true, false, "500", 5, false, blogId, wpcomFlag, wpVersion);
}
} //end loop
pd.dismiss();
if (blogCtr == 0){
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle("No Blogs Found");
String additionalText = "";
if (result.length > 0){
additionalText = " additional ";
}
dialogBuilder.setMessage("No " + additionalText + "blogs were found for that account.");
dialogBuilder.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Just close the window.
}
});
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
else{
//take them to the blog selection screen if there's more than one blog
if (blogCtr > 1){
LayoutInflater inflater = (LayoutInflater)AddAccount.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ListView lv = (ListView) inflater.inflate(R.layout.select_blogs_list, null);
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv.setItemsCanFocus(false);
ArrayAdapter<CharSequence> blogs = new ArrayAdapter<CharSequence>(AddAccount.this, R.layout.blogs_row, aBlogNames);
lv.setAdapter(blogs);
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle("Select Blogs");
dialogBuilder.setView(lv);
dialogBuilder.setNegativeButton("Add Selected", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
SparseBooleanArray selectedItems = lv.getCheckedItemPositions();
WordPressDB settingsDB = new WordPressDB(AddAccount.this);
for (int i=0; i<selectedItems.size();i++){
if (selectedItems.get(selectedItems.keyAt(i)) == true){
int rowID = selectedItems.keyAt(i);
success = settingsDB.addAccount(AddAccount.this, urls[rowID], blogNames[rowID], username, password, httpuser, httppassword, "Above Text", true, false, "500", 5, false, blogIds[rowID], wpcoms[rowID], wpVersions[rowID]);
}
}
Bundle bundle = new Bundle();
bundle.putString("returnStatus", "SAVE");
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
});
dialogBuilder.setPositiveButton("Add All", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
WordPressDB settingsDB = new WordPressDB(AddAccount.this);
for (int i=0;i<blogCtr;i++){
success = settingsDB.addAccount(AddAccount.this, urls[i], blogNames[i], username, password, httpuser, httppassword, "Above Text", true, false, "500", 5, false, blogIds[i], wpcoms[i], wpVersions[i]);
}
Bundle bundle = new Bundle();
bundle.putString("returnStatus", "SAVE");
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
});
dialogBuilder.setCancelable(true);
AlertDialog ad = dialogBuilder.create();
ad.setInverseBackgroundForced(true);
ad.show();
final Button addSelected = ad.getButton(AlertDialog.BUTTON_NEGATIVE);
addSelected.setEnabled(false);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
SparseBooleanArray selectedItems = lv.getCheckedItemPositions();
boolean isChecked = false;
for (int i=0; i<selectedItems.size();i++){
if (selectedItems.get(selectedItems.keyAt(i)) == true){
isChecked = true;
}
}
if (!isChecked){
addSelected.setEnabled(false);
}
else{
addSelected.setEnabled(true);
}
}
});
}
else {
success = settingsDB.addAccount(AddAccount.this, urls[0], blogNames[0], username, password, httpuser, httppassword, "Above Text", true, false, "500", 5, false, blogIds[0], wpcoms[0], wpVersions[0]);
Bundle bundle = new Bundle();
bundle.putString("returnStatus", "SAVE");
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
}
}
});
Object[] params = {
username,
password
};
method.call(params);
}
}
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// See which child activity is calling us back.
switch (requestCode) {
case R.id.settingsButton:
if (resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
httpuser = extras.getString("httpuser");
httppassword = extras.getString("httppassword");
}
default:
break;
}
}
@Override public boolean onKeyDown(int i, KeyEvent event) {
// only intercept back button press
if (i == KeyEvent.KEYCODE_BACK) {
Bundle bundle = new Bundle();
bundle.putString("returnStatus", "CANCEL");
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
}
return false; // propagate this keyevent
}
interface XMLRPCMethodCallback {
void callFinished(Object[] result);
}
class XMLRPCMethod extends Thread {
private String method;
private Object[] params;
private Handler handler;
private XMLRPCMethodCallback callBack;
public XMLRPCMethod(String method, XMLRPCMethodCallback callBack) {
this.method = method;
this.callBack = callBack;
handler = new Handler();
}
public void call() {
call(null);
}
public void call(Object[] params) {
this.params = params;
start();
}
@Override
public void run() {
try {
final Object[] result;
result = (Object[]) client.call(method, params);
handler.post(new Runnable() {
public void run() {
callBack.callFinished(result);
}
});
} catch (final XMLRPCFault e) {
handler.post(new Runnable() {
public void run() {
//e.printStackTrace();
pd.dismiss();
String message = e.getMessage();
if (message.contains("code 403")){
//invalid login
Thread shake = new Thread(){
public void run()
{
Animation shake = AnimationUtils.loadAnimation(AddAccount.this, R.anim.shake);
findViewById(R.id.section1).startAnimation(shake);
Toast.makeText(AddAccount.this, getResources().getString(R.string.invalid_login), Toast.LENGTH_SHORT).show();
}
};
runOnUiThread(shake);
}
else{
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle(getResources().getText(R.string.connection_error));
if (message.equals("HTTP status code: 404 != 200")){
message = "xmlrpc.php not found, please check your path";
}
dialogBuilder.setMessage(message);
dialogBuilder.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Just close the window.
}
});
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
}
});
} catch (final XMLRPCException e) {
handler.post(new Runnable() {
public void run() {
Throwable couse = e.getCause();
e.printStackTrace();
pd.dismiss();
if (couse instanceof HttpHostConnectException) {
} else {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(AddAccount.this);
dialogBuilder.setTitle(getResources().getText(R.string.connection_error));
String message = e.getMessage();
if (message.equals("HTTP status code: 404 != 200")){
message = "xmlrpc.php not found, please check your path";
}
dialogBuilder.setMessage(message);
dialogBuilder.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Just close the window.
}
});
dialogBuilder.setCancelable(true);
dialogBuilder.create().show();
}
e.printStackTrace();
}
});
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
//ignore orientation change
super.onConfigurationChanged(newConfig);
}
private String getRSDMetaTagHref(String urlString) {
//get the html code
InputStream in = getResponse(urlString);
//parse the html and get the attribute for xmlrpc endpoint
if(in != null) {
XmlPullParser parser = Xml.newPullParser();
try {
// auto-detect the encoding from the stream
parser.setInput(in, null);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT){
String name = null;
String rel="";
String type="";
String href="";
switch (eventType){
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase("link")){
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attrName = parser.getAttributeName(i);
String attrValue = parser.getAttributeValue(i);
if(attrName.equals("rel")){
rel = attrValue;
}
else if(attrName.equals("type"))
type = attrValue;
else if(attrName.equals("href"))
href = attrValue;
// Log.trace("attribute name: "+ parser.getAttributeName(i));
// Log.trace("attribute value: "+parser.getAttributeValue(i));
}
if(rel.equals("EditURI") && type.equals("application/rsd+xml")){
return href;
}
// currentMessage.setLink(parser.nextText());
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return null; //never found the rsd tag
}
private String getXMLRPCUrl(String urlString) {
//get the html code
InputStream in = getResponse(urlString);
//parse the html and get the attribute for xmlrpc endpoint
if(in != null) {
//try {
XmlPullParser parser = Xml.newPullParser();
try {
// auto-detect the encoding from the stream
parser.setInput(in, null);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT){
String name="";
String apiLink="";
switch (eventType){
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase("api")){
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attrName = parser.getAttributeName(i);
String attrValue = parser.getAttributeValue(i);
if(attrName.equals("name")){
name = attrValue;
}
else if(attrName.equals("apiLink")){
apiLink = attrValue;
}
// Log.trace("attribute name: "+ parser.getAttributeName(i));
// Log.trace("attribute value: "+parser.getAttributeValue(i));
}
if(name.equals("WordPress") ){
return apiLink;
}
// currentMessage.setLink(parser.nextText());
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return null; //never found the rsd tag
}
private InputStream getResponse(String urlString) {
// TODO Auto-generated method stub
InputStream in = null;
int response = -1;
URL url = null;
try {
url = new URL(urlString);
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return null;
}
URLConnection conn = null;
try {
conn = url.openConnection();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return null;
}
try{
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.addRequestProperty("user-agent", "Mozilla/5.0");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
return in;
}
}