]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/SaveTransactionTask.java
3c2cb447975cb3d7406e5ddcd57600a12d49c196
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / SaveTransactionTask.java
1 package net.ktnx.mobileledger;
2
3 import android.content.SharedPreferences;
4 import android.os.AsyncTask;
5 import android.util.Log;
6
7 import java.io.BufferedReader;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.net.HttpURLConnection;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Locale;
16 import java.util.Map;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import static java.lang.Thread.sleep;
21
22 class SaveTransactionTask extends AsyncTask<LedgerTransaction, Void, Void> {
23     private final TaskCallback task_callback;
24     private String token;
25     private String session;
26     private String backend_url;
27     private LedgerTransaction ltr;
28     protected String error;
29
30     private SharedPreferences pref;
31     void setPref(SharedPreferences pref) {
32         this.pref = pref;
33     }
34
35     SaveTransactionTask(TaskCallback callback) {
36         task_callback = callback;
37     }
38     private boolean send_ok() throws IOException {
39         HttpURLConnection http = NetworkUtil.prepare_connection(pref, "add");
40         http.setRequestMethod("POST");
41         http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
42         http.setRequestProperty("Accept", "*/*");
43         if ((session != null) && !session.isEmpty()) {
44             http.setRequestProperty("Cookie", String.format("_SESSION=%s", session));
45         }
46         http.setDoOutput(true);
47         http.setDoInput(true);
48
49         UrlEncodedFormData params = new UrlEncodedFormData();
50         params.add_pair("_formid", "identify-add");
51         if (token != null) params.add_pair("_token", token);
52         params.add_pair("date", ltr.getDate());
53         params.add_pair("description", ltr.getDescription());
54         {
55             Iterator<LedgerTransactionItem> items = ltr.getItemsIterator();
56             while (items.hasNext()) {
57                 LedgerTransactionItem item = items.next();
58                 params.add_pair("account", item.get_account_name());
59                 if (item.is_amount_set())
60                     params.add_pair("amount", String.format(Locale.US, "%1.2f", item.get_amount()));
61                 else params.add_pair("amount", "");
62             }
63         }
64
65         String body = params.toString();
66         http.addRequestProperty("Content-Length", String.valueOf(body.length()));
67
68         Log.d("network", "request header: " + http.getRequestProperties().toString());
69
70         try (OutputStream req = http.getOutputStream()) {
71             Log.d("network", "Request body: " + body);
72             req.write(body.getBytes("ASCII"));
73
74             try (InputStream resp = http.getInputStream()) {
75                 Log.d("update_accounts", String.valueOf(http.getResponseCode()));
76                 if (http.getResponseCode() == 303) {
77                     // everything is fine
78                     return true;
79                 } else if (http.getResponseCode() == 200) {
80                     // get the new cookie
81                     {
82                         Pattern sess_cookie_re = Pattern.compile("_SESSION=([^;]+);.*");
83
84                         Map<String, List<String>> header = http.getHeaderFields();
85                         List<String> cookie_header = header.get("Set-Cookie");
86                         if (cookie_header != null) {
87                             String cookie = cookie_header.get(0);
88                             Matcher m = sess_cookie_re.matcher(cookie);
89                             if (m.matches()) {
90                                 session = m.group(1);
91                                 Log.d("network", "new session is " + session);
92                             } else {
93                                 Log.d("network", "set-cookie: " + cookie);
94                                 Log.w("network", "Response Set-Cookie headers is not a _SESSION one");
95                             }
96                         } else {
97                             Log.w("network", "Response has no Set-Cookie header");
98                         }
99                     }
100                     // the token needs to be updated
101                     BufferedReader reader = new BufferedReader(new InputStreamReader(resp));
102                     Pattern re = Pattern.compile("<input type=\"hidden\" name=\"_token\" value=\"([^\"]+)\">");
103                     String line;
104                     while ((line = reader.readLine()) != null) {
105                         //Log.d("dump", line);
106                         Matcher m = re.matcher(line);
107                         if (m.matches()) {
108                             token = m.group(1);
109                             Log.d("save-transaction", line);
110                             Log.d("save-transaction", "Token=" + token);
111                             return false;       // retry
112                         }
113                     }
114                     throw new IOException("Can't find _token string");
115                 } else {
116                     throw new IOException(String.format("Error response code %d", http.getResponseCode()));
117                 }
118             }
119         }
120     }
121
122     @Override
123     protected Void doInBackground(LedgerTransaction... ledgerTransactions) {
124         error = null;
125         try {
126             backend_url = pref.getString("backend_url", "");
127             ltr = ledgerTransactions[0];
128
129             int tried = 0;
130             while (!send_ok()) {
131                 try {
132                     tried++;
133                     if (tried >= 2)
134                         throw new IOException(String.format("aborting after %d tries", tried));
135                     sleep(100);
136                 }
137                 catch (InterruptedException e) {
138                     e.printStackTrace();
139                 }
140             }
141         }
142         catch (Exception e) {
143             e.printStackTrace();
144             error = e.getMessage();
145         }
146
147         return null;
148     }
149
150     @Override
151     protected void onPostExecute(Void aVoid) {
152         super.onPostExecute(aVoid);
153         task_callback.done(error);
154     }
155 }