diff options
Diffstat (limited to 'src/org')
| -rw-r--r-- | src/org/slcl/Alert.java | 27 | ||||
| -rw-r--r-- | src/org/slcl/LoginActivity.java | 29 | ||||
| -rw-r--r-- | src/org/slcl/Main.java | 65 | ||||
| -rw-r--r-- | src/org/slcl/core/Connection.java | 56 | ||||
| -rw-r--r-- | src/org/slcl/core/Cookie.java | 39 | ||||
| -rw-r--r-- | src/org/slcl/core/Directory.java | 43 | ||||
| -rw-r--r-- | src/org/slcl/core/Login.java | 50 | ||||
| -rw-r--r-- | src/org/slcl/core/Result.java | 18 |
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; + } +} |
