aboutsummaryrefslogtreecommitdiff
path: root/src/org
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-05-18 00:16:22 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-05-28 08:30:24 +0200
commitee53ad2ccc88b91a1857e75714ae56068bd40952 (patch)
tree9f3be3aa809d2cfb54ab6d1269f57f6538a4de97 /src/org
parent40f6d425a4429b16936cc8bb4900a23c3362a123 (diff)
Diffstat (limited to 'src/org')
-rw-r--r--src/org/slcl/Alert.java27
-rw-r--r--src/org/slcl/LoginActivity.java29
-rw-r--r--src/org/slcl/Main.java65
-rw-r--r--src/org/slcl/core/Connection.java56
-rw-r--r--src/org/slcl/core/Cookie.java39
-rw-r--r--src/org/slcl/core/Directory.java43
-rw-r--r--src/org/slcl/core/Login.java50
-rw-r--r--src/org/slcl/core/Result.java18
8 files changed, 226 insertions, 101 deletions
diff --git a/src/org/slcl/Alert.java b/src/org/slcl/Alert.java
new file mode 100644
index 0000000..1b93550
--- /dev/null
+++ b/src/org/slcl/Alert.java
@@ -0,0 +1,27 @@
+package org.slcl;
+
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+
+public final class Alert {
+ public Alert(final Context c, final String message)
+ {
+ final AlertDialog.Builder b = new AlertDialog.Builder(c);
+
+ b.setMessage(message);
+ b.setPositiveButton("Close",
+ new DialogInterface.OnClickListener() {
+ public void onClick(final DialogInterface dialog,
+ final int id) {
+ dialog.cancel();
+ }
+ }
+ );
+
+ final AlertDialog d = b.create();
+
+ d.show();
+ }
+}
diff --git a/src/org/slcl/LoginActivity.java b/src/org/slcl/LoginActivity.java
index 79e2ed4..dd58b9b 100644
--- a/src/org/slcl/LoginActivity.java
+++ b/src/org/slcl/LoginActivity.java
@@ -20,6 +20,7 @@ package org.slcl;
import org.slcl.core.Cookie;
import org.slcl.core.Login;
+import org.slcl.core.Result;
import org.slcl.Directory;
import org.slcl.InternalFile;
import java.net.URLEncoder;
@@ -88,15 +89,14 @@ public final class LoginActivity extends Activity {
t.execute(p);
}
catch (final IOException e) {
- //error.setText("Exception: " + e.getMessage());
+ new Alert(LoginActivity.this, e.getMessage());
}
}
});
}
- // https://stackoverflow.com/questions/6053602/what-arguments-are-passed-into-asynctaskarg1-arg2-arg3
private final class LoginTask
- extends AsyncTask<LoginParams, String, String>
+ extends AsyncTask<LoginParams, Void, Result<String>>
{
ProgressDialog dialog;
@@ -108,7 +108,7 @@ public final class LoginActivity extends Activity {
}
@Override
- protected String doInBackground(final LoginParams... params)
+ protected Result<String> doInBackground(final LoginParams... params)
{
try {
final LoginParams p = params[0];
@@ -120,27 +120,28 @@ public final class LoginActivity extends Activity {
final Cookie c = new Cookie(p.username, cookie);
c.store(f.getFile());
- return "";
+ return new Result<String>();
} catch (final IOException e) {
- System.out.println(e.getMessage());
- return e.getMessage();
+ return new Result<String>("Could not connect: "
+ + e.getMessage());
}
}
@Override
- protected void onProgressUpdate(final String... text)
+ protected void onProgressUpdate(final Void... text)
{
}
@Override
- protected void onPostExecute(final String result)
+ protected void onPostExecute(final Result<String> result)
{
- Intent intent = new Intent(LoginActivity.this, Directory.class);
-
dialog.dismiss();
- startActivity(intent);
- // TODO: review errors.
- //error.setText("Exception: " + e.getMessage());
+
+ if (result.success) {
+ startActivity(new Intent(LoginActivity.this, Directory.class));
+ } else {
+ new Alert(LoginActivity.this, result.error);
+ }
}
}
}
diff --git a/src/org/slcl/Main.java b/src/org/slcl/Main.java
index 8ac8c55..34a3b92 100644
--- a/src/org/slcl/Main.java
+++ b/src/org/slcl/Main.java
@@ -35,59 +35,34 @@ public final class Main extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState)
{
- final LoadTask t = new LoadTask();
-
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- t.execute();
- }
-
- private final class LoadTask extends AsyncTask<String, String, Cookie>
- {
- ProgressDialog dialog;
-
- @Override
- protected void onPreExecute()
- {
- dialog = dialog.show(Main.this, "ProgressDialog",
- "Retrieving credentials");
- }
-
- @Override
- protected Cookie doInBackground(final String... args)
- {
- try {
- final InternalFile f = new InternalFile(
- getApplicationContext(), "login");
- final Cookie c = new Cookie(f.getFile());
- return c;
- } catch (final IOException e) {
- System.out.println(e.getMessage());
- return null;
- }
- }
+ final Cookie c = getLogin();
+ final Intent intent;
- @Override
- protected void onProgressUpdate(final String... params)
- {
+ if (c == null) {
+ intent = new Intent(Main.this, LoginActivity.class);
+ } else {
+ intent = new Intent(Main.this, Directory.class);
+ // TODO: split cookie with ';' (expiration date, etc.).
+ intent.putExtra(Directory.EXTRA_ID, c.getCookie());
}
- @Override
- protected void onPostExecute(final Cookie cookie)
- {
- final Intent intent;
+ startActivity(intent);
+ }
- if (cookie == null) {
- intent = new Intent(Main.this, LoginActivity.class);
- } else {
- intent = new Intent(Main.this, Directory.class);
- // TODO: split cookie with ';' (expiration date, etc.).
- intent.putExtra(Directory.EXTRA_ID, cookie.getCookie());
- }
+ private Cookie getLogin()
+ {
+ try {
+ final Context context = getApplicationContext();
+ final InternalFile f = new InternalFile(context, "login");
+ final Cookie cookie = new Cookie(f.getFile());
- dialog.dismiss();
- startActivity(intent);
+ return cookie;
+ } catch (final IOException e) {
+ System.out.println(e.getMessage());
+ return null;
}
}
}
diff --git a/src/org/slcl/core/Connection.java b/src/org/slcl/core/Connection.java
new file mode 100644
index 0000000..9c6cad5
--- /dev/null
+++ b/src/org/slcl/core/Connection.java
@@ -0,0 +1,56 @@
+/*
+ * slcl-android, an Android frontend for slcl
+ * Copyright (C) 2023-2024 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.slcl.core;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import javax.net.ssl.HttpsURLConnection;
+
+public final class Connection
+{
+ final HttpURLConnection c;
+
+ public Connection(final boolean https, final String orig_url)
+ throws IOException
+ {
+ String url = orig_url;
+
+ if (!url.startsWith("https://") && https) {
+ url = "https://" + url;
+ }
+ else if (!url.startsWith("http://")) {
+ url = "http://" + url;
+ }
+
+ URL u = new URL(url);
+
+ if (https) {
+ c = (HttpsURLConnection)u.openConnection();
+ }
+ else {
+ c = (HttpURLConnection)u.openConnection();
+ }
+ }
+
+ public HttpURLConnection getConnection()
+ {
+ return c;
+ }
+}
diff --git a/src/org/slcl/core/Cookie.java b/src/org/slcl/core/Cookie.java
index 86f64b5..3bdd320 100644
--- a/src/org/slcl/core/Cookie.java
+++ b/src/org/slcl/core/Cookie.java
@@ -24,8 +24,9 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
@@ -50,7 +51,14 @@ public final class Cookie {
final FileInputStream fis = new FileInputStream(f);
final InputStreamReader ir = new InputStreamReader(fis);
final BufferedReader r = new BufferedReader(ir);
- final Results res = from_data(null, r.readLine());
+ final String data = r.readLine();
+
+ if (data == null) {
+ fis.close();
+ throw new IOException("empty file");
+ }
+
+ final Results res = from_data(null, data);
username = res.username;
cookie = res.cookie;
@@ -59,8 +67,8 @@ public final class Cookie {
}
private final class CookieDate {
- final private String FMT = "EEE, dd MMM yyyy hh:mm:ss z";
- Date date;
+ final private String FMT = "EEE, dd MMM yyyy HH:mm:ss z";
+ final DateTime date;
public CookieDate(final String[] tokens) throws IOException
{
@@ -77,14 +85,17 @@ public final class Cookie {
continue;
}
- ParsePosition pos = new ParsePosition(0);
- final SimpleDateFormat fmt = new SimpleDateFormat(FMT);
- final Date d = fmt.parse(date_tokens[1], pos);
+ final DateTimeFormatter fmt = DateTimeFormat.forPattern(FMT);
- if (d != null) {
- // TODO: check pos.
- date = d;
+ try {
+ final DateTime dt = fmt.parseDateTime(date_tokens[1]);
+
+ date = dt;
return;
+ } catch (final IllegalArgumentException e) {
+ throw new IOException(e.getMessage());
+ } catch (final UnsupportedOperationException e) {
+ throw new IOException(e.getMessage());
}
}
@@ -93,12 +104,10 @@ public final class Cookie {
public String toString()
{
- final SimpleDateFormat fmt = new SimpleDateFormat(FMT);
-
- return fmt.format(date, null, null).toString();
+ return date.toString(FMT);
}
- public Date getDate() {
+ public DateTime getDate() {
return date;
}
}
diff --git a/src/org/slcl/core/Directory.java b/src/org/slcl/core/Directory.java
new file mode 100644
index 0000000..1ac91e4
--- /dev/null
+++ b/src/org/slcl/core/Directory.java
@@ -0,0 +1,43 @@
+/*
+ * slcl-android, an Android frontend for slcl
+ * Copyright (C) 2023-2024 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.slcl.core;
+
+import org.slcl.core.Connection;
+import org.slcl.core.Cookie;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+
+public final class Directory
+{
+ String[] files, dirs;
+
+ public Directory(final Cookie cookie, final boolean https,
+ final String url, final String path) throws IOException
+ {
+ final Connection conn = new Connection(https, url + "/user" + path);
+ final HttpURLConnection c = conn.getConnection();
+
+ c.setRequestMethod("GET");
+ c.setInstanceFollowRedirects(false);
+ c.setReadTimeout(5000);
+
+ OutputStream os = c.getOutputStream();
+ }
+}
diff --git a/src/org/slcl/core/Login.java b/src/org/slcl/core/Login.java
index d5b9267..e52a01a 100644
--- a/src/org/slcl/core/Login.java
+++ b/src/org/slcl/core/Login.java
@@ -18,45 +18,26 @@
package org.slcl.core;
+import org.slcl.core.Connection;
import java.io.OutputStream;
import java.io.IOException;
-import java.net.URL;
-import java.net.URLConnection;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
public final class Login {
- public String login(final boolean https, String url, final String username,
- final String password) throws IOException {
-
- if (!url.startsWith("https://") && https) {
- url = "https://" + url;
- }
- else if (!url.startsWith("http://")) {
- url = "http://" + url;
- }
-
- url += "/login";
-
- final String data = "username=" + username + "&password=" + password;
-
- URL u = new URL(url);
- HttpURLConnection c;
-
- if (https) {
- c = (HttpsURLConnection)u.openConnection();
- }
- else {
- c = (HttpURLConnection)u.openConnection();
- }
+ public String login(final boolean https, final String url,
+ final String username, final String password) throws IOException
+ {
+ final Connection conn = new Connection(https, url + "/login");
+ final HttpURLConnection c = conn.getConnection();
c.setRequestMethod("POST");
c.setInstanceFollowRedirects(false);
c.setReadTimeout(5000);
- OutputStream os = c.getOutputStream();
+ final OutputStream os = c.getOutputStream();
+ final String data = "username=" + username + "&password=" + password;
os.write(data.getBytes());
@@ -74,6 +55,21 @@ public final class Login {
{
final Map<String,List<String>> headers = c.getHeaderFields();
final List<String> cookies = headers.get("Set-Cookie");
+ final List<String> locations = headers.get("Location");
+
+ if (locations == null) {
+ throw new IOException("Expected Location header");
+ } else if (locations.size() != 1) {
+ throw new IOException("Expected only 1 Location header");
+ }
+
+ final String location = locations.toArray(new String[0])[0],
+ exp_location = "/user/";
+
+ if (!location.equals(exp_location)) {
+ throw new IOException("Expected redirection to "
+ + exp_location + ", got \"" + location + "\"");
+ }
if (cookies != null) {
if (cookies.size() != 1) {
diff --git a/src/org/slcl/core/Result.java b/src/org/slcl/core/Result.java
new file mode 100644
index 0000000..2bffdb4
--- /dev/null
+++ b/src/org/slcl/core/Result.java
@@ -0,0 +1,18 @@
+package org.slcl.core;
+
+public final class Result<T> {
+ public final boolean success;
+ public final T error;
+
+ public Result()
+ {
+ success = true;
+ error = null;
+ }
+
+ public Result(final T error)
+ {
+ success = false;
+ this.error = error;
+ }
+}