From: Bartek Przybylski Date: Sat, 24 Dec 2011 21:54:11 +0000 (+0100) Subject: https for unsigned certificates in logging and uploading X-Git-Tag: oc-android-1.4.3~500 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/2bc41ee3315feb483e4b92873df8f7dd3bb5499c?ds=inline https for unsigned certificates in logging and uploading --- diff --git a/.classpath b/.classpath index f6f1092a..8be29c71 100644 --- a/.classpath +++ b/.classpath @@ -5,11 +5,13 @@ - - - - - + + + + + + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a5281fc9..a625c01a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -16,12 +16,6 @@ - - - @@ -38,7 +32,7 @@ - + @@ -74,12 +68,7 @@ - - - - - - + \ No newline at end of file diff --git a/default.properties b/default.properties deleted file mode 100644 index 46769a72..00000000 --- a/default.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=android-7 diff --git a/lib/android-support-v4.jar b/lib/android-support-v4.jar new file mode 100644 index 00000000..b254ef5f Binary files /dev/null and b/lib/android-support-v4.jar differ diff --git a/lib/commons-httpclient-contrib-3.0.jar b/lib/commons-httpclient-contrib-3.0.jar new file mode 100644 index 00000000..805ccee5 Binary files /dev/null and b/lib/commons-httpclient-contrib-3.0.jar differ diff --git a/lib/httpclient-4.1.2.jar b/lib/httpclient-4.1.2.jar new file mode 100644 index 00000000..b3cdb4cd Binary files /dev/null and b/lib/httpclient-4.1.2.jar differ diff --git a/lib/httpclient-cache-4.1.2.jar b/lib/httpclient-cache-4.1.2.jar new file mode 100644 index 00000000..6b7bcce5 Binary files /dev/null and b/lib/httpclient-cache-4.1.2.jar differ diff --git a/lib/httpcore-4.1.2.jar b/lib/httpcore-4.1.2.jar new file mode 100644 index 00000000..66ae90b0 Binary files /dev/null and b/lib/httpcore-4.1.2.jar differ diff --git a/lib/httpmime-4.1.2.jar b/lib/httpmime-4.1.2.jar new file mode 100644 index 00000000..eea3b3ff Binary files /dev/null and b/lib/httpmime-4.1.2.jar differ diff --git a/lib/not-yet-commons-ssl-0.3.11.jar b/lib/not-yet-commons-ssl-0.3.11.jar new file mode 100644 index 00000000..7b564277 Binary files /dev/null and b/lib/not-yet-commons-ssl-0.3.11.jar differ diff --git a/project.properties b/project.properties new file mode 100644 index 00000000..5a709453 --- /dev/null +++ b/project.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-7 diff --git a/src/eu/alefzero/owncloud/FileDownloader.java b/src/eu/alefzero/owncloud/FileDownloader.java new file mode 100644 index 00000000..1631f498 --- /dev/null +++ b/src/eu/alefzero/owncloud/FileDownloader.java @@ -0,0 +1,141 @@ +package eu.alefzero.owncloud; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.UnknownHostException; +import java.util.Date; + +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.protocol.BasicHttpContext; + +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.webdav.HttpPropFind; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.os.IBinder; +import android.util.Log; +import android.widget.FrameLayout; + +public class FileDownloader extends Service { + static final String EXTRA_ACCOUNT = "ACCOUNT"; + static final String EXTRA_FILE_PATH = "FILE_PATH"; + static final String TAG = "OC_FileDownloader"; + + NotificationManager nm; + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_FILE_PATH)) { + Log.e(TAG, "Not enough information provided in intent"); + return START_NOT_STICKY; + } + + nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + + Account account = intent.getParcelableExtra(EXTRA_ACCOUNT); + String file_path = intent.getStringExtra(EXTRA_FILE_PATH); + AccountManager am = (AccountManager)getSystemService(ACCOUNT_SERVICE); + Uri oc_url = Uri.parse(am.getUserData(account, AccountAuthenticator.KEY_OC_URL)); + + DefaultHttpClient client = new DefaultHttpClient(); + Log.d(TAG, oc_url.toString()); + HttpGet query = new HttpGet(oc_url + file_path); + query.setHeader("Content-type", "text/xml"); + query.setHeader("User-Agent", "Android-ownCloud"); + + BasicHttpContext httpContext = new BasicHttpContext(); + BasicScheme basicAuth = new BasicScheme(); + httpContext.setAttribute("preemptive-auth", basicAuth); + + String username = account.name.split("@")[0]; + String password = ""; + try { + password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true); + } catch (OperationCanceledException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (AuthenticatorException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + if (am.getUserData(account, AccountAuthenticator.KEY_OC_URL) == null) { + + } + + client.getCredentialsProvider().setCredentials( + new AuthScope(oc_url.getHost(), oc_url.getPort()==-1?80:oc_url.getPort()), + new UsernamePasswordCredentials(username, password) + ); + + HttpHost host = new HttpHost(oc_url.getHost(), oc_url.getPort()==-1?80:oc_url.getPort()); + + Notification n = new Notification(R.drawable.icon, "Downloading file", System.currentTimeMillis()); + PendingIntent pi = PendingIntent.getActivity(this, 1, new Intent(this, OwnCloudMainScreen.class), 0); + n.setLatestEventInfo(this, "A", "B", pi); + nm.notify(1, n); + + HttpResponse response = null; + try { + response = client.execute(host, query, httpContext); + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + File sdCard = Environment.getExternalStorageDirectory(); + File dir = new File (sdCard.getAbsolutePath() + "/owncloud"); + dir.mkdirs(); + File file = new File(dir, "filename"); + + try { + FileOutputStream f = new FileOutputStream(file); + byte[] b = new byte[(int)response.getEntity().getContentLength()]; + response.getEntity().getContent().read(b); + f.write(b); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + return START_NOT_STICKY; + } + +} diff --git a/src/eu/alefzero/owncloud/FileListActionListAdapter.java b/src/eu/alefzero/owncloud/FileListActionListAdapter.java index 522257ec..212a6f28 100644 --- a/src/eu/alefzero/owncloud/FileListActionListAdapter.java +++ b/src/eu/alefzero/owncloud/FileListActionListAdapter.java @@ -21,7 +21,6 @@ package eu.alefzero.owncloud; import java.io.File; import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta; import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; import android.accounts.Account; import android.accounts.AccountManager; @@ -30,14 +29,10 @@ import android.content.Intent; import android.database.Cursor; import android.database.DataSetObserver; import android.net.Uri; -import android.provider.MediaStore.Images.Media; -import android.sax.StartElementListener; import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.TextView; diff --git a/src/eu/alefzero/owncloud/OwnCloudMainScreen.java b/src/eu/alefzero/owncloud/OwnCloudMainScreen.java index 2eb478af..614058b4 100644 --- a/src/eu/alefzero/owncloud/OwnCloudMainScreen.java +++ b/src/eu/alefzero/owncloud/OwnCloudMainScreen.java @@ -18,6 +18,10 @@ package eu.alefzero.owncloud; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.LinkedList; import java.util.Stack; @@ -36,6 +40,7 @@ import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.Menu; @@ -276,13 +281,33 @@ public class OwnCloudMainScreen extends ListActivity { try { Intent i = (Intent) getListAdapter().getItem(position); if (i.hasExtra("toDownload")) { + + Uri data = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath() + "/owncloud/filename"); + Log.d("DUPA", data.toString()); + File f = new File(data.toString()); + FileInputStream fis = new FileInputStream(f); + byte buffer[] = new byte[512]; + fis.read(buffer); + Log.d("DUPA", new String(buffer)); + + //Intent intent = new Intent(this, FileDownloader.class); + /*intent.putExtra(FileDownloader.EXTRA_FILE_PATH, "/docsy.py"); + intent.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount); + startService(intent); + /* if (i.getBooleanExtra("toDownload", false)) { startActivityForResult(i, 200); } else { startActivity(i); - } + }*/ } - } catch (ClassCastException e) {} + } catch (ClassCastException e) {} catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } diff --git a/src/eu/alefzero/owncloud/OwnCloudUploader.java b/src/eu/alefzero/owncloud/OwnCloudUploader.java deleted file mode 100644 index 5f2c194c..00000000 --- a/src/eu/alefzero/owncloud/OwnCloudUploader.java +++ /dev/null @@ -1,495 +0,0 @@ -package eu.alefzero.owncloud; - -import java.io.File; -import java.sql.Date; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Stack; - -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.FileEntity; -import org.apache.http.entity.mime.MultipartEntity; -import org.apache.http.entity.mime.content.FileBody; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.BasicHttpContext; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.ListActivity; -import android.app.ProgressDialog; -import android.app.AlertDialog.Builder; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; -import android.provider.MediaStore.Images.Media; -import android.util.Log; -import android.view.View; -import android.view.Window; -import android.view.ViewGroup.LayoutParams; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.SimpleCursorAdapter; -import android.widget.Toast; -import android.widget.AdapterView.OnItemClickListener; -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.owncloud.db.ProviderMeta; -import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; -import eu.alefzero.webdav.HttpMkCol; -import eu.alefzero.webdav.WebdavUtils; - -public class OwnCloudUploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { - private static final String TAG = "ownCloudUploader"; - - private Account mAccount; - private AccountManager mAccountManager; - private String mUsername, mPassword; - private Cursor mCursor; - private Stack mParents; - private Thread mUploadThread; - private Handler mHandler; - private ArrayList mStreamsToUpload; - - private final static int DIALOG_NO_ACCOUNT = 0; - private final static int DIALOG_WAITING = 1; - private final static int DIALOG_NO_STREAM = 2; - private final static int DIALOG_MULTIPLE_ACCOUNT = 3; - private final static int DIALOG_GET_DIRNAME = 4; - - private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mParents = new Stack(); - mHandler = new Handler(); - if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { - prepareStreamsToUpload(); - mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); - if (accounts.length == 0) { - Log.i(TAG, "No ownCloud account is available"); - showDialog(DIALOG_NO_ACCOUNT); - } else if (accounts.length > 1) { - Log.i(TAG, "More then one ownCloud is available"); - showDialog(DIALOG_MULTIPLE_ACCOUNT); - } else { - mAccount = accounts[0]; - setContentView(R.layout.uploader_layout); - populateDirectoryList(); - } - } else { - showDialog(DIALOG_NO_STREAM); - } - } - - @Override - protected Dialog onCreateDialog(final int id) { - final AlertDialog.Builder builder = new Builder(this); - switch (id) { - case DIALOG_WAITING: - ProgressDialog pDialog = new ProgressDialog(this); - pDialog.setIndeterminate(false); - pDialog.setCancelable(false); - pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); - return pDialog; - case DIALOG_NO_ACCOUNT: - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.uploader_wrn_no_account_title); - builder.setMessage(R.string.uploader_wrn_no_account_text); - builder.setCancelable(false); - builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { - // using string value since in API7 this constatn is not defined - // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS - // and Settings.EXTRA_AUTHORITIES - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } else { - // since in API7 there is no direct call for account setup, so we need to - // show our own AccountSetupAcricity, get desired results and setup - // everything for ourself - Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); - startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); - } - } - }); - builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - return builder.create(); - case DIALOG_GET_DIRNAME: - final EditText dirName = new EditText(getBaseContext()); - builder.setView(dirName); - builder.setTitle(R.string.uploader_info_dirname); - String pathToUpload; - if (mParents.empty()) { - pathToUpload = "/"; - } else { - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - mCursor.moveToFirst(); - pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); - } - a a = new a(pathToUpload, dirName); - builder.setPositiveButton(R.string.common_ok, a); - builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - return builder.create(); - case DIALOG_MULTIPLE_ACCOUNT: - CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; - for (int i = 0; i < ac.length; ++i) { - ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; - } - builder.setTitle(R.string.common_choose_account); - builder.setItems(ac, new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; - populateDirectoryList(); - } - }); - builder.setCancelable(true); - builder.setOnCancelListener(new OnCancelListener() { - public void onCancel(DialogInterface dialog) { - dialog.cancel(); - finish(); - } - }); - return builder.create(); - default: - throw new IllegalArgumentException("Unknown dialog id: " + id); - } - } - - class a implements OnClickListener { - String mPath; - EditText mDirname; - public a(String path, EditText dirname) { - mPath = path; mDirname = dirname; - } - public void onClick(DialogInterface dialog, int which) { - showDialog(DIALOG_WAITING); - mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true)); - mUploadThread.start(); - } - } - - @Override - public void onBackPressed() { - - if (mParents.size()==0) { - super.onBackPressed(); - return; - } else if (mParents.size() == 1) { - mParents.pop(); - mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - } else { - mParents.pop(); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - } - - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - } - - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (!mCursor.moveToPosition(position)) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); - mParents.push(_id); - - mCursor.close(); - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id), - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=?", - new String[]{"DIR"}, - null); - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - getListView().invalidate(); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.uploader_choose_folder: - String pathToUpload = null; - if (mParents.empty()) { - pathToUpload = "/"; - } else { - mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - mCursor.moveToFirst(); - pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + - mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); - } - - showDialog(DIALOG_WAITING); - mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler)); - mUploadThread.start(); - - break; - case android.R.id.button1: // dynamic action for create aditional dir - showDialog(DIALOG_GET_DIRNAME); - break; - default: - throw new IllegalArgumentException("Wrong element clicked"); - } - } - - public void onUploadComplete(boolean uploadSucc, String message) { - dismissDialog(DIALOG_WAITING); - Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message); - if (uploadSucc) { - Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show(); - } - finish(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); - if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { - dismissDialog(DIALOG_NO_ACCOUNT); - if (resultCode == RESULT_CANCELED) { - finish(); - } - Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); - if (accounts.length == 0) { - showDialog(DIALOG_NO_ACCOUNT); - } else { - // there is no need for checking for is there more then one account at this point - // since account setup can set only one account at time - mAccount = accounts[0]; - populateDirectoryList(); - } - } - } - - private void populateDirectoryList() { - mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@')); - mPassword = mAccountManager.getPassword(mAccount); - setContentView(R.layout.uploader_layout); - mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, - null, - ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", - new String[]{"DIR", mAccount.name}, - null); - - ListView lv = getListView(); - lv.setOnItemClickListener(this); - SimpleCursorAdapter sca = new SimpleCursorAdapter(this, - R.layout.uploader_list_item_layout, - mCursor, - new String[]{ProviderTableMeta.FILE_NAME}, - new int[]{R.id.textView1}); - setListAdapter(sca); - Button btn = (Button) findViewById(R.id.uploader_choose_folder); - btn.setOnClickListener(this); - // insert create new directory for multiple items uploading - if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - Button createDirBtn = new Button(this); - createDirBtn.setId(android.R.id.button1); - createDirBtn.setText(R.string.uploader_btn_create_dir_text); - createDirBtn.setOnClickListener(this); - ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - } - } - - private void prepareStreamsToUpload() { - if (getIntent().getAction().equals(Intent.ACTION_SEND)) { - mStreamsToUpload = new ArrayList(); - mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); - } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { - mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); - } else { - // unknow action inserted - throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); - } - } - - public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) { - ContentValues cv = new ContentValues(); - cv.put(ProviderTableMeta.FILE_NAME, filename); - cv.put(ProviderTableMeta.FILE_PATH, filepath); - cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath); - cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date())); - cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType); - cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength); - cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); - Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath); - if (!mParents.empty()) { - Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), - null, - null, - null, - null); - c.moveToFirst(); - cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); - c.close(); - } - getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); - } - - class BackgroundUploader implements Runnable { - private ArrayList mUploadStreams; - private Handler mHandler; - private String mUploadPath; - private boolean mCreateDir; - - public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, - Handler handler) { - mUploadStreams = streamsToUpload; - mHandler = handler; - mUploadPath = pathToUpload.replace(" ", "%20"); - mCreateDir = false; - } - - public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, - Handler handler, boolean createDir) { - mUploadStreams = streamsToUpload; - mHandler = handler; - mUploadPath = pathToUpload.replace(" ", "%20"); - mCreateDir = createDir; - } - - public void run() { - boolean any_failed = false; - DefaultHttpClient httpClient = new DefaultHttpClient(); - Uri uri = Uri.parse(mAccountManager.getUserData(mAccount, - AccountAuthenticator.KEY_OC_URL)); - httpClient.getCredentialsProvider().setCredentials( - new AuthScope(uri.getHost(), (uri.getPort() == -1) ? 80 : uri - .getPort()), - new UsernamePasswordCredentials(mUsername, mPassword)); - BasicHttpContext httpContext = new BasicHttpContext(); - BasicScheme basicAuth = new BasicScheme(); - httpContext.setAttribute("preemptive-auth", basicAuth); - HttpHost targetHost = new HttpHost(uri.getHost(), (uri.getPort() == -1) - ? 80 - : uri.getPort(), (uri.getScheme() == "https") ? "https" : "http"); - - // create last directory in path if nessesary - if (mCreateDir) { - HttpMkCol method = new HttpMkCol(uri.toString() + mUploadPath + "/"); - method.setHeader("User-Agent", "Android-ownCloud"); - try { - httpClient.execute(targetHost, method, httpContext); - Log.i(TAG, "Creating dir completed"); - } catch (final Exception e) { - e.printStackTrace(); - mHandler.post(new Runnable() { - public void run() { - OwnCloudUploader.this.onUploadComplete(false, e.getLocalizedMessage()); - } - }); - return; - } - } - - for (int i = 0; i < mUploadStreams.size(); ++i) { - final Cursor c = getContentResolver().query((Uri)mUploadStreams.get(i), null, null, null, null); - c.moveToFirst(); - - HttpPut method = new HttpPut(uri.toString() + mUploadPath + "/" - + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)).replace(" ", "%20")); - method.setHeader("Content-type", c.getString(c.getColumnIndex(Media.MIME_TYPE))); - method.setHeader("User-Agent", "Android-ownCloud"); - - try { - FileBody fb = new FileBody(new File(c.getString(c.getColumnIndex(Media.DATA))), c.getString(c.getColumnIndex(Media.MIME_TYPE))); - MultipartEntity entity = new MultipartEntity(); - final FileEntity fileEntity = new FileEntity(new File(c.getString(c.getColumnIndex(Media.DATA))), - c.getString(c.getColumnIndex(Media.MIME_TYPE))); - - entity.addPart(c.getString(c.getColumnIndex(Media.DISPLAY_NAME)).replace(" ", "%20"), fb); - - method.setEntity(fileEntity); - Log.i(TAG, "executing:" + method.getRequestLine().toString()); - - httpClient.execute(targetHost, method, httpContext); - mHandler.post(new Runnable() { - public void run() { - OwnCloudUploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)), - c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), - mUploadPath + (mUploadPath.equals("/")?"":"/"), - fileEntity.getContentType().getValue(), - fileEntity.getContentLength()+""); - } - }); - Log.i(TAG, "Uploading, done"); - - } catch (final Exception e) { - any_failed = true; - mHandler.post(new Runnable() { - public void run() { - OwnCloudUploader.this.onUploadComplete(false, c.getString(c.getColumnIndex(Media.DISPLAY_NAME))+ " " + e.getLocalizedMessage()); - } - }); - } - } - if (!any_failed) { - mHandler.post(new Runnable() { - public void run() { - OwnCloudUploader.this.onUploadComplete(true, "Success"); - } - }); - } - Bundle bundle = new Bundle(); - bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); - //ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, bundle); - - } - - } - -} diff --git a/src/eu/alefzero/owncloud/Uploader.java b/src/eu/alefzero/owncloud/Uploader.java new file mode 100644 index 00000000..66dec569 --- /dev/null +++ b/src/eu/alefzero/owncloud/Uploader.java @@ -0,0 +1,423 @@ +package eu.alefzero.owncloud; + +import java.util.ArrayList; +import java.util.Stack; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.app.AlertDialog.Builder; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnCancelListener; +import android.content.DialogInterface.OnClickListener; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Parcelable; +import android.provider.MediaStore.Images.Media; +import android.util.Log; +import android.view.View; +import android.view.Window; +import android.view.ViewGroup.LayoutParams; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; +import eu.alefzero.owncloud.authenticator.AccountAuthenticator; +import eu.alefzero.owncloud.db.ProviderMeta; +import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta; +import eu.alefzero.webdav.WebdavUtils; + +public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener { + private static final String TAG = "ownCloudUploader"; + + private Account mAccount; + private AccountManager mAccountManager; + private String mUsername, mPassword; + private Cursor mCursor; + private Stack mParents; + private Thread mUploadThread; + private Handler mHandler; + private ArrayList mStreamsToUpload; + + private final static int DIALOG_NO_ACCOUNT = 0; + private final static int DIALOG_WAITING = 1; + private final static int DIALOG_NO_STREAM = 2; + private final static int DIALOG_MULTIPLE_ACCOUNT = 3; + private final static int DIALOG_GET_DIRNAME = 4; + + private final static int REQUEST_CODE_SETUP_ACCOUNT = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().requestFeature(Window.FEATURE_NO_TITLE); + mParents = new Stack(); + mHandler = new Handler(); + if (getIntent().hasExtra(Intent.EXTRA_STREAM)) { + prepareStreamsToUpload(); + mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE); + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE); + if (accounts.length == 0) { + Log.i(TAG, "No ownCloud account is available"); + showDialog(DIALOG_NO_ACCOUNT); + } else if (accounts.length > 1) { + Log.i(TAG, "More then one ownCloud is available"); + showDialog(DIALOG_MULTIPLE_ACCOUNT); + } else { + mAccount = accounts[0]; + setContentView(R.layout.uploader_layout); + populateDirectoryList(); + } + } else { + showDialog(DIALOG_NO_STREAM); + } + } + + @Override + protected Dialog onCreateDialog(final int id) { + final AlertDialog.Builder builder = new Builder(this); + switch (id) { + case DIALOG_WAITING: + ProgressDialog pDialog = new ProgressDialog(this); + pDialog.setIndeterminate(false); + pDialog.setCancelable(false); + pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading)); + return pDialog; + case DIALOG_NO_ACCOUNT: + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setTitle(R.string.uploader_wrn_no_account_title); + builder.setMessage(R.string.uploader_wrn_no_account_text); + builder.setCancelable(false); + builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) { + // using string value since in API7 this constatn is not defined + // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS + // and Settings.EXTRA_AUTHORITIES + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE}); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } else { + // since in API7 there is no direct call for account setup, so we need to + // show our own AccountSetupAcricity, get desired results and setup + // everything for ourself + Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class); + startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT); + } + } + }); + builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + return builder.create(); + case DIALOG_GET_DIRNAME: + final EditText dirName = new EditText(getBaseContext()); + builder.setView(dirName); + builder.setTitle(R.string.uploader_info_dirname); + String pathToUpload; + if (mParents.empty()) { + pathToUpload = "/"; + } else { + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + mCursor.moveToFirst(); + pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); + } + a a = new a(pathToUpload, dirName); + builder.setPositiveButton(R.string.common_ok, a); + builder.setNegativeButton(R.string.common_cancel, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + return builder.create(); + case DIALOG_MULTIPLE_ACCOUNT: + CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length]; + for (int i = 0; i < ac.length; ++i) { + ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name; + } + builder.setTitle(R.string.common_choose_account); + builder.setItems(ac, new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which]; + populateDirectoryList(); + } + }); + builder.setCancelable(true); + builder.setOnCancelListener(new OnCancelListener() { + public void onCancel(DialogInterface dialog) { + dialog.cancel(); + finish(); + } + }); + return builder.create(); + default: + throw new IllegalArgumentException("Unknown dialog id: " + id); + } + } + + class a implements OnClickListener { + String mPath; + EditText mDirname; + public a(String path, EditText dirname) { + mPath = path; mDirname = dirname; + } + public void onClick(DialogInterface dialog, int which) { + showDialog(DIALOG_WAITING); + mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true)); + mUploadThread.start(); + } + } + + @Override + public void onBackPressed() { + + if (mParents.size()==0) { + super.onBackPressed(); + return; + } else if (mParents.size() == 1) { + mParents.pop(); + mCursor = managedQuery(ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + } else { + mParents.pop(); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()), + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + } + + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + } + + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (!mCursor.moveToPosition(position)) { + throw new IndexOutOfBoundsException("Incorrect item selected"); + } + String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID)); + mParents.push(_id); + + mCursor.close(); + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id), + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=?", + new String[]{"DIR"}, + null); + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + getListView().invalidate(); + } + + public void onClick(View v) { + switch (v.getId()) { + case R.id.uploader_choose_folder: + String pathToUpload = null; + if (mParents.empty()) { + pathToUpload = "/"; + } else { + mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + mCursor.moveToFirst(); + pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) + + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20"); + } + + showDialog(DIALOG_WAITING); + mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler)); + mUploadThread.start(); + + break; + case android.R.id.button1: // dynamic action for create aditional dir + showDialog(DIALOG_GET_DIRNAME); + break; + default: + throw new IllegalArgumentException("Wrong element clicked"); + } + } + + public void onUploadComplete(boolean uploadSucc, String message) { + dismissDialog(DIALOG_WAITING); + Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message); + if (uploadSucc) { + Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show(); + } + finish(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode); + if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) { + dismissDialog(DIALOG_NO_ACCOUNT); + if (resultCode == RESULT_CANCELED) { + finish(); + } + Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE); + if (accounts.length == 0) { + showDialog(DIALOG_NO_ACCOUNT); + } else { + // there is no need for checking for is there more then one account at this point + // since account setup can set only one account at time + mAccount = accounts[0]; + populateDirectoryList(); + } + } + } + + private void populateDirectoryList() { + mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@')); + mPassword = mAccountManager.getPassword(mAccount); + setContentView(R.layout.uploader_layout); + mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI, + null, + ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?", + new String[]{"DIR", mAccount.name}, + null); + + ListView lv = getListView(); + lv.setOnItemClickListener(this); + SimpleCursorAdapter sca = new SimpleCursorAdapter(this, + R.layout.uploader_list_item_layout, + mCursor, + new String[]{ProviderTableMeta.FILE_NAME}, + new int[]{R.id.textView1}); + setListAdapter(sca); + Button btn = (Button) findViewById(R.id.uploader_choose_folder); + btn.setOnClickListener(this); + // insert create new directory for multiple items uploading + if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + Button createDirBtn = new Button(this); + createDirBtn.setId(android.R.id.button1); + createDirBtn.setText(R.string.uploader_btn_create_dir_text); + createDirBtn.setOnClickListener(this); + ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + } + } + + private void prepareStreamsToUpload() { + if (getIntent().getAction().equals(Intent.ACTION_SEND)) { + mStreamsToUpload = new ArrayList(); + mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); + } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) { + mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM); + } else { + // unknow action inserted + throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction()); + } + } + + public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) { + ContentValues cv = new ContentValues(); + cv.put(ProviderTableMeta.FILE_NAME, filename); + cv.put(ProviderTableMeta.FILE_PATH, filepath); + cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath); + cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date())); + cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType); + cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength); + cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name); + Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath); + if (!mParents.empty()) { + Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), + null, + null, + null, + null); + c.moveToFirst(); + cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID))); + c.close(); + } + getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv); + } + + class BackgroundUploader implements Runnable { + private ArrayList mUploadStreams; + private Handler mHandler; + private String mUploadPath; + private boolean mCreateDir; + + public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, + Handler handler) { + mUploadStreams = streamsToUpload; + mHandler = handler; + mUploadPath = pathToUpload.replace(" ", "%20"); + mCreateDir = false; + } + + public BackgroundUploader(String pathToUpload, ArrayList streamsToUpload, + Handler handler, boolean createDir) { + mUploadStreams = streamsToUpload; + mHandler = handler; + mUploadPath = pathToUpload.replace(" ", "%20"); + mCreateDir = createDir; + } + + public void run() { + WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount, + AccountAuthenticator.KEY_OC_URL))); + wdc.setCredentials(mUsername, mPassword); + wdc.allowUnsignedCertificates(); + + // create last directory in path if nessesary + if (mCreateDir) { + wdc.createDirectory(mUploadPath); + } + + for (int i = 0; i < mUploadStreams.size(); ++i) { + final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null); + c.moveToFirst(); + + if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)), + mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), + c.getString(c.getColumnIndex(Media.MIME_TYPE)))) { + mHandler.post(new Runnable() { + public void run() { + Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME))); + } + }); + } + } + mHandler.post(new Runnable() { + public void run() { + Uploader.this.onUploadComplete(true, null); + } + }); + } + + } + +} diff --git a/src/eu/alefzero/owncloud/WebdavClient.java b/src/eu/alefzero/owncloud/WebdavClient.java new file mode 100644 index 00000000..9ff1ed9c --- /dev/null +++ b/src/eu/alefzero/owncloud/WebdavClient.java @@ -0,0 +1,146 @@ +package eu.alefzero.owncloud; + +import java.io.File; + +import org.apache.http.HttpHost; +import org.apache.http.HttpVersion; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.params.ConnManagerPNames; +import org.apache.http.conn.params.ConnPerRouteBean; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.FileEntity; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.BasicHttpContext; + +import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory; +import eu.alefzero.webdav.HttpMkCol; + +import android.net.Uri; +import android.util.Log; + +public class WebdavClient { + private DefaultHttpClient mHttpClient; + private BasicHttpContext mHttpContext; + private HttpHost mTargetHost; + private SchemeRegistry mSchemeRegistry; + private Uri mUri; + final private static String TAG = "WebdavClient"; + + WebdavClient(Uri uri) { + mUri = uri; + mSchemeRegistry = new SchemeRegistry(); + setupHttpClient(); + } + + void setCredentials(String username, String password) { + // determine default port for http or https + int targetPort = mTargetHost.getPort() == -1 ? + ( mUri.getScheme().equals("https") ? 443 : 80) + : mUri.getPort(); + + mHttpClient.getCredentialsProvider().setCredentials( + new AuthScope(mUri.getHost(), targetPort), + new UsernamePasswordCredentials(username, password)); + BasicScheme basicAuth = new BasicScheme(); + mHttpContext.setAttribute("preemptive-auth", basicAuth); + } + + void allowUnsignedCertificates() { + // https + mSchemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); + } + + boolean downloadFile(String filepath) { + return true; + } + + void getFileList(String dirPath) { + + } + + boolean putFile(String localFile, + String remoteTarget, + String contentType) { + boolean result = true; + HttpPut method = new HttpPut(mUri.toString() + remoteTarget.replace(" ", "%20")); + method.setHeader("Content-type", contentType); + method.setHeader("Host", mUri.getHost()); + method.setHeader("User-Agent", "Android-ownCloud"); + + try { + FileBody fb = new FileBody(new File(localFile, contentType)); + final FileEntity fileEntity = new FileEntity(new File(localFile), contentType); + + method.setEntity(fileEntity); + Log.i(TAG, "executing:" + method.getRequestLine().toString()); + + mHttpClient.execute(mTargetHost, method, mHttpContext); + /*mHandler.post(new Runnable() { + public void run() { + Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)), + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)), + mUploadPath + (mUploadPath.equals("/")?"":"/"), + fileEntity.getContentType().getValue(), + fileEntity.getContentLength()+""); + } + }); + Log.i(TAG, "Uploading, done"); +*/ + Log.i(TAG, "Uploading, done"); + } catch (final Exception e) { + Log.i(TAG, e.getLocalizedMessage()); + result = false; + } + + return result; + } + + public boolean createDirectory(String path) { + HttpMkCol method = new HttpMkCol(mUri.toString() + path + "/"); + method.setHeader("User-Agent", "Android-ownCloud"); + + try { + mHttpClient.execute(mTargetHost, method, mHttpContext); + Log.i(TAG, "Creating dir completed"); + } catch (final Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + private void setupHttpClient() { + // http scheme + mSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + mSchemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); + + HttpParams params = new BasicHttpParams(); + params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); + params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); + params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + + mHttpContext = new BasicHttpContext(); + ClientConnectionManager cm = new ThreadSafeClientConnManager(params, mSchemeRegistry); + + int port = mUri.getPort() == -1 ? + mUri.getScheme().equals("https") ? 443 : 80 + : mUri.getPort(); + + mTargetHost = new HttpHost(mUri.getHost(), port, mUri.getScheme()); + + mHttpClient = new DefaultHttpClient(cm, params); + } +} diff --git a/src/eu/alefzero/owncloud/authenticator/AuthUtils.java b/src/eu/alefzero/owncloud/authenticator/AuthUtils.java index e4396a48..c5068868 100644 --- a/src/eu/alefzero/owncloud/authenticator/AuthUtils.java +++ b/src/eu/alefzero/owncloud/authenticator/AuthUtils.java @@ -22,17 +22,51 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; + +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; + +import org.apache.http.impl.client.DefaultHttpClient; + +import org.apache.commons.httpclient.auth.BasicScheme; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpHead; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.conn.params.ConnManagerPNames; +import org.apache.http.conn.params.ConnPerRouteBean; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.conn.SingleClientConnManager; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; + import android.content.Context; import android.os.Handler; import android.util.Log; @@ -103,10 +137,25 @@ public class AuthUtils { sendResult(false, handler, context, "Server error: " + mResultMsg); return false; } - + public static boolean tryGetWebdav(URL url, String username, String pwd, Handler handler, Context context) { - DefaultHttpClient c = new DefaultHttpClient(); + SchemeRegistry schemeRegistry = new SchemeRegistry(); + // http scheme + schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + // https scheme + schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443)); + + HttpParams params = new BasicHttpParams(); + params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30); + params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30)); + params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + + ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); + + DefaultHttpClient c = new DefaultHttpClient(cm, params); + c.getCredentialsProvider().setCredentials( new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()), new UsernamePasswordCredentials(username, pwd)); @@ -117,8 +166,9 @@ public class AuthUtils { localcontext.setAttribute("preemptive-auth", basicAuth); HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1) ? 80 - : url.getPort(), (url.getProtocol() == "https") ? "https" : "http"); + : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http"); HttpHead httpget = new HttpHead(url.toString()); + httpget.setHeader("Host", url.getHost()); HttpResponse response = null; try { response = c.execute(targetHost, httpget, localcontext); @@ -134,6 +184,7 @@ public class AuthUtils { return false; } String status = response.getStatusLine().toString(); + status = status.split(" ")[1]; Log.i("AuthUtils", "Status returned: " + status); if (status.equals("200")) { diff --git a/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java b/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java new file mode 100644 index 00000000..f057b8bd --- /dev/null +++ b/src/eu/alefzero/owncloud/authenticator/EasySSLSocketFactory.java @@ -0,0 +1,138 @@ +package eu.alefzero.owncloud.authenticator; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; + +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.scheme.LayeredSocketFactory; +import org.apache.http.conn.scheme.SocketFactory; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; + +/** + * This socket factory will create ssl socket that accepts self signed + * certificate + * + * @author olamy + * @version $Id: EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse + * $ + * @since 1.2.3 + */ +public class EasySSLSocketFactory implements SocketFactory, + LayeredSocketFactory { + + private SSLContext sslcontext = null; + + private static SSLContext createEasySSLContext() throws IOException { + try { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new TrustManager[] { new EasyX509TrustManager( + null) }, null); + return context; + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + private SSLContext getSSLContext() throws IOException { + if (this.sslcontext == null) { + this.sslcontext = createEasySSLContext(); + } + return this.sslcontext; + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, + * java.lang.String, int, java.net.InetAddress, int, + * org.apache.http.params.HttpParams) + */ + public Socket connectSocket(Socket sock, String host, int port, + InetAddress localAddress, int localPort, HttpParams params) + throws IOException, UnknownHostException, ConnectTimeoutException { + int connTimeout = HttpConnectionParams.getConnectionTimeout(params); + int soTimeout = HttpConnectionParams.getSoTimeout(params); + + InetSocketAddress remoteAddress = new InetSocketAddress(host, port); + SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); + + if ((localAddress != null) || (localPort > 0)) { + // we need to bind explicitly + if (localPort < 0) { + localPort = 0; // indicates "any" + } + InetSocketAddress isa = new InetSocketAddress(localAddress, + localPort); + sslsock.bind(isa); + } + + sslsock.connect(remoteAddress, connTimeout); + sslsock.setSoTimeout(soTimeout); + return sslsock; + + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#createSocket() + */ + public Socket createSocket() throws IOException { + return getSSLContext().getSocketFactory().createSocket(); + } + + /** + * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) + */ + public boolean isSecure(Socket socket) throws IllegalArgumentException { + return true; + } + + /** + * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, + * java.lang.String, int, boolean) + */ + public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) throws IOException, UnknownHostException { + return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); + } + + // ------------------------------------------------------------------- + // javadoc in org.apache.http.conn.scheme.SocketFactory says : + // Both Object.equals() and Object.hashCode() must be overridden + // for the correct operation of some connection managers + // ------------------------------------------------------------------- + + public boolean equals(Object obj) { + return ((obj != null) && obj.getClass().equals( + EasySSLSocketFactory.class)); + } + + public int hashCode() { + return EasySSLSocketFactory.class.hashCode(); + } + +} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java b/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java new file mode 100644 index 00000000..d6323bbc --- /dev/null +++ b/src/eu/alefzero/owncloud/authenticator/EasyX509TrustManager.java @@ -0,0 +1,93 @@ +package eu.alefzero.owncloud.authenticator; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +/** + * @author olamy + * @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $ + * @since 1.2.3 + */ +public class EasyX509TrustManager + implements X509TrustManager +{ + + private X509TrustManager standardTrustManager = null; + + /** + * Constructor for EasyX509TrustManager. + */ + public EasyX509TrustManager( KeyStore keystore ) + throws NoSuchAlgorithmException, KeyStoreException + { + super(); + TrustManagerFactory factory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() ); + factory.init( keystore ); + TrustManager[] trustmanagers = factory.getTrustManagers(); + if ( trustmanagers.length == 0 ) + { + throw new NoSuchAlgorithmException( "no trust manager found" ); + } + this.standardTrustManager = (X509TrustManager) trustmanagers[0]; + } + + /** + * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) + */ + public void checkClientTrusted( X509Certificate[] certificates, String authType ) + throws CertificateException + { + standardTrustManager.checkClientTrusted( certificates, authType ); + } + + /** + * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) + */ + public void checkServerTrusted( X509Certificate[] certificates, String authType ) + throws CertificateException + { + if ( ( certificates != null ) && ( certificates.length == 1 ) ) + { + certificates[0].checkValidity(); + } + else + { + //standardTrustManager.checkServerTrusted( certificates, authType ); + } + } + + /** + * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() + */ + public X509Certificate[] getAcceptedIssuers() + { + return this.standardTrustManager.getAcceptedIssuers(); + } + +} \ No newline at end of file diff --git a/src/eu/alefzero/owncloud/cp2.java b/src/eu/alefzero/owncloud/cp2.java deleted file mode 100644 index 9d7ba0d6..00000000 --- a/src/eu/alefzero/owncloud/cp2.java +++ /dev/null @@ -1,47 +0,0 @@ -package eu.alefzero.owncloud; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class cp2 extends ContentProvider { - - @Override - public int delete(Uri arg0, String arg1, String[] arg2) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public String getType(Uri arg0) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Uri insert(Uri arg0, ContentValues arg1) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean onCreate() { - // TODO Auto-generated method stub - return false; - } - - @Override - public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, - String arg4) { - // TODO Auto-generated method stub - return null; - } - - @Override - public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { - // TODO Auto-generated method stub - return 0; - } - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java b/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java deleted file mode 100644 index 61564d5c..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/ContactSyncAdapter.java +++ /dev/null @@ -1,133 +0,0 @@ -package eu.alefzero.owncloud.syncadapter; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; - -import android.accounts.AccountManager; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.ByteArrayEntity; - -import eu.alefzero.owncloud.authenticator.AccountAuthenticator; -import eu.alefzero.webdav.HttpPropFind; - -import android.accounts.Account; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; -import android.content.ContentProviderClient; -import android.content.Context; -import android.content.SyncResult; -import android.content.res.AssetFileDescriptor; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.provider.ContactsContract; -import android.util.Log; - -public class ContactSyncAdapter extends AbstractOwnCloudSyncAdapter { - - private static final String TAG = "ContactSyncAdapter"; - - public ContactSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - - @Override - public synchronized void onPerformSync( - Account account, - Bundle extras, - String authority, - ContentProviderClient provider, - SyncResult syncResult) { - - this.setAccount(account); - this.setContentProvider(provider); - - // TODO find all contacts on ownCloud that not synced or the sync date is behind than the last sync date - Cursor cursor = getContacts(); - if (cursor != null && cursor.getCount() > 0) { - while (cursor.moveToNext()) { - String id = cursor.getString( - cursor.getColumnIndex(ContactsContract.Contacts._ID)); - String lookup = cursor.getString( - cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); - - try { - FileInputStream fis = getContactVcard(lookup); - - HttpPut query = new HttpPut( - getUri() + - "/addressbooks/"+ - getAccount().name.split("@")[0]+ - "/default/"+ - lookup+ - ".vcf" - ); - byte[] b = new byte[fis.available()]; - fis.read(b); - query.setEntity(new ByteArrayEntity(b)); - HttpResponse response = fireRawRequest(query); - if(201 != response.getStatusLine().getStatusCode()) { - syncResult.stats.numIoExceptions++; - } - // TODO make a webdav request based on the stream - // TODO send request to the ownCloud server - // TODO mark the current contact as synced - where to store? - fis.close(); - } catch (IOException e) { - syncResult.stats.numIoExceptions++; - } catch (OperationCanceledException e) { - //TODO maybe to a better break here - return; - } catch (AuthenticatorException e) { - syncResult.stats.numAuthExceptions++; - } - } - } - } - - protected Uri getUri() { - Uri uri = Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_CONTACT_URL)); - return uri; - } - - /** - * Returns the vCard based on the LookupKey for Contact as Stream - * - * @param lookupKey - * @return - * @throws IOException - */ - private FileInputStream getContactVcard(String lookupKey) throws IOException { - Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey); - AssetFileDescriptor fd = getContext().getContentResolver().openAssetFileDescriptor(uri, "r"); - return fd.createInputStream(); - } - - /** - * Obtains the contact list. - * - * @return A cursor for for accessing the contact list. - */ - private Cursor getContacts() - { - // Run query - Uri uri = ContactsContract.Contacts.CONTENT_URI; - String[] projection = new String[] { - ContactsContract.Contacts._ID, - ContactsContract.Contacts.LOOKUP_KEY - }; - - boolean showInvisible = false; - String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + - (showInvisible ? "0" : "1") + "'"; - String[] selectionArgs = null; - String sortOrder = ContactsContract.Contacts._ID + " DESC"; - - return getContext().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); - } - - - -} diff --git a/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java b/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java deleted file mode 100644 index 2dd7661c..00000000 --- a/src/eu/alefzero/owncloud/syncadapter/ContactSyncService.java +++ /dev/null @@ -1,31 +0,0 @@ -package eu.alefzero.owncloud.syncadapter; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class ContactSyncService extends Service { - private static final Object syncAdapterLock = new Object(); - private static AbstractOwnCloudSyncAdapter concretSyncAdapter = null; - - /* - * {@inheritDoc} - */ - @Override - public void onCreate() { - synchronized (syncAdapterLock) { - if (concretSyncAdapter == null) { - concretSyncAdapter = new ContactSyncAdapter(getApplicationContext(), true); - } - } - } - - /* - * {@inheritDoc} - */ - @Override - public IBinder onBind(Intent intent) { - return concretSyncAdapter.getSyncAdapterBinder(); - } - -}