package app.fedilab.android.client; /* Copyright 2019 Thomas Schneider * * This file is a part of Fedilab * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * Fedilab 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 General * Public License for more details. * * You should have received a copy of the GNU General Public License along with Fedilab; if not, * see . */ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Objects; import app.fedilab.android.R; import app.fedilab.android.activities.MainActivity; import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask; import app.fedilab.android.client.Entities.Account; import app.fedilab.android.client.Entities.Application; import app.fedilab.android.client.Entities.Attachment; import app.fedilab.android.client.Entities.Error; import app.fedilab.android.client.Entities.InstanceNodeInfo; import app.fedilab.android.client.Entities.Mention; import app.fedilab.android.client.Entities.Notification; import app.fedilab.android.client.Entities.Relationship; import app.fedilab.android.client.Entities.Results; import app.fedilab.android.client.Entities.Status; import app.fedilab.android.fragments.DisplayNotificationsFragment; import app.fedilab.android.helper.Helper; import app.fedilab.android.sqlite.AccountDAO; import app.fedilab.android.sqlite.Sqlite; import app.fedilab.android.sqlite.TimelineCacheDAO; import static app.fedilab.android.helper.Helper.PREF_KEY_OAUTH_TOKEN; /** * Created by Thomas on 02/02/2019. * Manage Calls to the REST API for GNU */ public class GNUAPI { private Account account; private final Context context; private List accounts; private List statuses; private int tootPerPage, accountPerPage, notificationPerPage; private int actionCode; private String instance; private String prefKeyOauthTokenT; private APIResponse apiResponse; private Error APIError; public GNUAPI(Context context) { this.context = context; SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); tootPerPage = sharedpreferences.getInt(Helper.SET_TOOT_PER_PAGE, Helper.TOOTS_PER_PAGE); accountPerPage = Helper.ACCOUNTS_PER_PAGE; notificationPerPage = Helper.NOTIFICATIONS_PER_PAGE; this.prefKeyOauthTokenT = sharedpreferences.getString(PREF_KEY_OAUTH_TOKEN, null); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); if (Helper.getLiveInstance(context) != null) this.instance = Helper.getLiveInstance(context); else { SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(context)); Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); if (account == null) { APIError = new Error(); APIError.setError(context.getString(R.string.toast_error)); return; } this.instance = account.getInstance().trim(); } apiResponse = new APIResponse(); APIError = null; } public GNUAPI(Context context, String instance, String token) { this.context = context; if (context == null) { apiResponse = new APIResponse(); APIError = new Error(); return; } SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); tootPerPage = sharedpreferences.getInt(Helper.SET_TOOT_PER_PAGE, Helper.TOOTS_PER_PAGE); accountPerPage = Helper.ACCOUNTS_PER_PAGE; notificationPerPage = Helper.NOTIFICATIONS_PER_PAGE; if (instance != null) this.instance = instance; else this.instance = Helper.getLiveInstance(context); if (token != null) this.prefKeyOauthTokenT = token; else this.prefKeyOauthTokenT = sharedpreferences.getString(PREF_KEY_OAUTH_TOKEN, null); apiResponse = new APIResponse(); APIError = null; } /** * Parse json response for several groups * * @param jsonArray JSONArray * @return List */ private static List parseGroups(JSONArray jsonArray) { List groups = new ArrayList<>(); try { int i = 0; while (i < jsonArray.length()) { JSONObject resobj = jsonArray.getJSONObject(i); Account group = parseGroups(resobj); i++; groups.add(group); } } catch (JSONException e) { e.printStackTrace(); } return groups; } /** * Parse json response for unique group * * @param resobj JSONObject * @return Account */ private static Account parseGroups(JSONObject resobj) { Account group = new Account(); try { group.setId(resobj.get("id").toString()); //group.setFollowers_count(resobj.getInt("admin_count")); //group.setBlocked(resobj.getBoolean("blocked")); group.setCreated_at(Helper.mstStringToDate(resobj.getString("created"))); group.setNote(resobj.getString("description")); group.setDisplay_name(resobj.getString("fullname")); //group.setHomepage(resobj.getString("homepage")); group.setUsername(resobj.getString("nickname")); group.setAvatar(resobj.getString("homepage_logo")); //group.setLocation(resobj.getString("location")); group.setFollowing(resobj.getBoolean("member")); group.setFollowers_count(resobj.getInt("member_count")); //group.setMini_logo(resobj.getString("mini_logo")); //group.setModified(Helper.mstStringToDate(context, resobj.getString("modified"))); group.setAcct("!" + resobj.getString("nickname")); group.setAvatar_static(resobj.getString("original_logo")); group.setHeader(resobj.getString("stream_logo")); group.setUrl(resobj.getString("url")); } catch (JSONException | ParseException e) { e.printStackTrace(); } return group; } /** * Parse json response for several status * * @param jsonArray JSONArray * @return List */ static List parseStatuses(Context context, JSONArray jsonArray) { List statuses = new ArrayList<>(); try { int i = 0; while (i < jsonArray.length()) { JSONObject resobj = jsonArray.getJSONObject(i); Status status = parseStatuses(context, resobj); i++; statuses.add(status); } } catch (JSONException e) { e.printStackTrace(); } return statuses; } /** * Parse json response for unique status * * @param resobj JSONObject * @return Status */ private static Status parseStatuses(Context context, JSONObject resobj) { return parseStatuses(context, resobj, true); } /** * Parse json response for unique status * * @param resobj JSONObject * @return Status */ private static Status parseStatuses(Context context, JSONObject resobj, boolean recursive) { Status status = new Status(); try { status.setId(resobj.get("id").toString()); try { status.setUri(resobj.get("uri").toString()); } catch (Exception ignored) { status.setUri(resobj.get("id").toString()); } status.setCreated_at(Helper.mstStringToDate(resobj.get("created_at").toString())); if (resobj.has("in_reply_to_status_id")) status.setIn_reply_to_id(resobj.get("in_reply_to_status_id").toString()); if (resobj.has("in_reply_to_user_id")) status.setIn_reply_to_account_id(resobj.get("in_reply_to_user_id").toString()); status.setSensitive(false); status.setSpoiler_text(null); if (!resobj.has("sender")) status.setVisibility("public"); else status.setVisibility("direct"); if (resobj.has("geo")) status.setLanguage(resobj.isNull("geo") ? null : resobj.getString("geo")); if (resobj.has("external_url")) status.setUrl(resobj.get("external_url").toString()); //Retrieves attachments try { JSONArray arrayAttachement = resobj.getJSONArray("attachments"); ArrayList attachments = new ArrayList<>(parseAttachmentResponse(arrayAttachement)); status.setMedia_attachments(attachments); } catch (Exception ignored) { status.setMedia_attachments(new ArrayList<>()); } status.setCard(null); try { status.setConversationId(resobj.get("statusnet_conversation_id").toString()); } catch (Exception ignored) { if (resobj.has("friendica_parent_uri")) status.setConversationId(resobj.get("friendica_parent_uri").toString()); else status.setConversationId(resobj.get("id").toString()); } //Retrieves mentions List mentions = new ArrayList<>(); if (resobj.has("attentions")) { JSONArray arrayMention = resobj.getJSONArray("attentions"); for (int j = 0; j < arrayMention.length(); j++) { JSONObject menObj = arrayMention.getJSONObject(j); Mention mention = new Mention(); mention.setId(menObj.get("id").toString()); mention.setUrl(menObj.get("profileurl").toString()); mention.setAcct(menObj.get("screen_name").toString()); mention.setUsername(menObj.get("fullname").toString()); mentions.add(mention); } status.setMentions(mentions); } else { status.setMentions(new ArrayList<>()); } //Retrieves tags status.setTags(null); //Retrieves emjis status.setEmojis(new ArrayList<>()); //Retrieve Application Application application = new Application(); try { resobj.getJSONObject("source"); application.setName(resobj.getJSONObject("source").toString()); application.setWebsite(resobj.getJSONObject("source_link").toString()); } catch (Exception e) { application = new Application(); } status.setApplication(application); if (resobj.has("user")) status.setAccount(parseAccountResponse(resobj.getJSONObject("user"))); else if (resobj.has("sender")) status.setAccount(parseAccountResponse(resobj.getJSONObject("sender"))); if (resobj.has("statusnet_html")) status.setContent(context, resobj.get("statusnet_html").toString()); else if (resobj.has("text")) status.setContent(context, resobj.get("text").toString()); if (resobj.has("fave_num")) status.setFavourites_count(resobj.getInt("fave_num")); else status.setFavourites_count(0); if (resobj.has("repeat_num")) status.setReblogs_count(resobj.getInt("repeat_num")); else status.setReblogs_count(0); status.setReplies_count(0); try { status.setReblogged(resobj.getBoolean("repeated")); } catch (Exception e) { status.setReblogged(false); } try { status.setFavourited(resobj.getBoolean("favorited")); } catch (Exception e) { status.setFavourited(false); } if (resobj.has("friendica_activities") && resobj.getJSONObject("friendica_activities").has("like")) { status.setFavourited(false); JSONArray jsonArray = resobj.getJSONObject("friendica_activities").getJSONArray("like"); SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); for (int i = 0; i < jsonArray.length(); i++) { JSONObject like = jsonArray.getJSONObject(i); if (like.getString("id").equals(userId)) { status.setFavourited(true); break; } } } status.setMuted(false); status.setPinned(false); try { if (recursive) { status.setReblog(parseStatuses(context, resobj.getJSONObject("retweeted_status"), false)); } } catch (Exception ignored) { status.setReblog(null); } if (status.getContent().contains(status.getUri())) status.setNotice(true); } catch (JSONException | ParseException e) { e.printStackTrace(); } status.setViewType(context); Status.fillSpan(new WeakReference<>(context), status); return status; } /** * Parse json response an unique account * * @param resobj JSONObject * @return Account */ public static Account parseAccountResponse(JSONObject resobj) { Account account = new Account(); try { if (resobj.has("id_str")) { account.setId(resobj.getString("id_str")); } else { account.setId(resobj.get("id").toString()); } if (resobj.has("ostatus_uri")) { account.setUuid(resobj.get("ostatus_uri").toString()); } else { if (resobj.has("id_str")) { account.setUuid(resobj.getString("id_str")); } else { account.setUuid(resobj.get("id").toString()); } } account.setUsername(resobj.getString("screen_name")); account.setAcct(resobj.getString("screen_name")); account.setDisplay_name(resobj.getString("name")); account.setLocked(Boolean.parseBoolean(resobj.get("protected").toString())); account.setFollowers_count(resobj.getInt("followers_count")); account.setFollowing_count(resobj.getInt("friends_count")); account.setStatuses_count(resobj.getInt("statuses_count")); account.setNote(resobj.get("description").toString()); account.setBot(false); account.setMoved_to_account(null); account.setUrl(resobj.get("url").toString()); account.setAvatar(resobj.get("profile_image_url_https").toString()); account.setAvatar_static(resobj.get("profile_image_url_https").toString()); if (!resobj.isNull("background_image")) { account.setHeader(resobj.get("background_image").toString()); account.setHeader_static(resobj.get("background_image").toString()); } else { account.setHeader("null"); account.setHeader_static("null"); } if (resobj.has("cid")) account.setSocial("FRIENDICA"); else account.setSocial("GNU"); account.setEmojis(new ArrayList<>()); account.setCreated_at(Helper.mstStringToDate(resobj.get("created_at").toString())); } catch (JSONException | ParseException e) { e.printStackTrace(); } return account; } /** * Parse json response for list of relationship * * @param jsonArray JSONArray * @return List */ private static List parseAttachmentResponse(JSONArray jsonArray) { List attachments = new ArrayList<>(); try { int i = 0; while (i < jsonArray.length()) { JSONObject resobj = jsonArray.getJSONObject(i); Attachment attachment = parseAttachmentResponse(resobj); attachments.add(attachment); i++; } } catch (JSONException ignored) { } return attachments; } /** * Parse json response an unique attachment * * @param resobj JSONObject * @return Relationship */ private static Attachment parseAttachmentResponse(JSONObject resobj) { Attachment attachment = new Attachment(); try { if (resobj.has("id")) attachment.setId(resobj.get("id").toString()); if (resobj.has("url")) { attachment.setUrl(resobj.getString("url")); attachment.setPreview_url(resobj.getString("url")); attachment.setRemote_url(resobj.getString("url")); } if (attachment.getUrl().endsWith("png") || attachment.getUrl().endsWith("jpg") || attachment.getUrl().endsWith("jpeg")) { attachment.setType("image"); } else if (attachment.getUrl().endsWith("gif") || attachment.getUrl().endsWith("apng")) { attachment.setType("gifv"); } else if (attachment.getUrl().endsWith("mp4")) { attachment.setType("video"); } else { attachment.setType("web"); } try { attachment.setDescription(resobj.get("description").toString()); } catch (JSONException ignore) { } try { attachment.setRemote_url(resobj.get("url").toString()); } catch (JSONException ignore) { } try { attachment.setPreview_url(resobj.get("thumb_url").toString()); } catch (JSONException ignore) { } try { attachment.setMeta(resobj.get("meta").toString()); } catch (JSONException ignore) { } try { attachment.setText_url(resobj.get("text_url").toString()); } catch (JSONException ignore) { } } catch (JSONException ignored) { } return attachment; } /** * Parse json response an unique attachment * * @param resobj JSONObject * @return Relationship */ public static Attachment parseUploadedAttachmentResponse(JSONObject resobj) { Attachment attachment = new Attachment(); try { if (resobj.has("media_id")) attachment.setId(resobj.get("media_id").toString()); if (resobj.has("image") && resobj.getJSONObject("image").has("image_type")) attachment.setType("Image"); else if (resobj.has("image") && resobj.getJSONObject("gif").has("image_type")) attachment.setType("GifV"); else attachment.setType("video"); try { attachment.setRemote_url(resobj.get("url").toString()); } catch (JSONException ignore) { } try { attachment.setPreview_url(resobj.get("thumb_url").toString()); } catch (JSONException ignore) { } if (resobj.has("image") && resobj.getJSONObject("image").has("friendica_preview_url")) { attachment.setUrl(resobj.getJSONObject("image").getString("friendica_preview_url")); attachment.setPreview_url(resobj.getJSONObject("image").getString("friendica_preview_url")); attachment.setRemote_url(resobj.getJSONObject("image").getString("friendica_preview_url")); } if (resobj.has("media_url")) attachment.setUrl(resobj.get("media_url").toString()); try { attachment.setDescription(resobj.get("description").toString()); } catch (JSONException ignore) { } try { attachment.setMeta(resobj.get("meta").toString()); } catch (JSONException ignore) { } try { attachment.setText_url(resobj.get("text_url").toString()); } catch (JSONException ignore) { } } catch (JSONException e) { e.printStackTrace(); } return attachment; } /*** * Verifiy credential of the authenticated user *synchronously* * @return Account */ public Account verifyCredentials() { account = new Account(); InstanceNodeInfo nodeinfo = new API(context).displayNodeInfo(instance); String social = null; if (nodeinfo != null) { social = nodeinfo.getName(); } try { String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/account/verify_credentials.json"), 60, null, prefKeyOauthTokenT); account = parseAccountResponse(new JSONObject(response)); if (social != null) { account.setSocial(social.toUpperCase()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return account; } /** * Returns an account * * @param accountId String account fetched * @return Account entity */ public Account getAccount(String accountId) { account = new Account(); HashMap params = new HashMap<>(); params.put("user_id", accountId); try { String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/users/show.json"), 60, params, prefKeyOauthTokenT); account = parseAccountResponse(new JSONObject(response)); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return account; } /** * Retrieves group *synchronously* * * @param max_id String id max * @return APIResponse */ @SuppressWarnings("SameParameterValue") public APIResponse getGroups(String max_id) { return getGroups(max_id, null); } /** * Retrieves group *synchronously* * * @param max_id String id max * @param since_id String since the id * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getGroups(String max_id, String since_id) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); accounts = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/statusnet/groups/list.json"), 60, params, prefKeyOauthTokenT); accounts = parseGroups(new JSONArray(response)); if (accounts.size() > 0) { apiResponse.setSince_id(accounts.get(0).getId()); apiResponse.setMax_id(accounts.get(accounts.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setAccounts(accounts); return apiResponse; } /** * Retrieves group timeline *synchronously* * * @param groupName String id group * @param max_id String id max * @return APIResponse */ public APIResponse getGroupTimeline(String groupName, String max_id) { return getGroupTimeline(groupName, max_id, null); } /** * Retrieves group timeline *synchronously* * * @param groupName String id group * @param max_id String id max * @param since_id String since the id * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getGroupTimeline(String groupName, String max_id, String since_id) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String url; url = getAbsoluteUrl(String.format("/statusnet/groups/timeline/%s.json", groupName)); String response = httpsConnection.get(url, 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Returns a relationship between the authenticated account and an account * * @param accountId String account fetched * @return Relationship entity */ public Relationship getRelationship(String accountId) { Relationship relationship = null; HashMap params = new HashMap<>(); try { String response; if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.GNU) { params.put("target_id", accountId); response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/friendships/show.json"), 60, params, prefKeyOauthTokenT); relationship = parseRelationshipResponse(new JSONObject(response)); } else if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.FRIENDICA) { params.put("user_id", accountId); response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/users/show.json"), 60, params, prefKeyOauthTokenT); JSONObject resobj = new JSONObject(response); try { relationship = new Relationship(); relationship.setId(resobj.get("id").toString()); relationship.setFollowing(resobj.getBoolean("following")); relationship.setFollowed_by(resobj.getBoolean("follow_request_sent")); relationship.setBlocking(resobj.getBoolean("statusnet_blocking")); try { relationship.setMuting(resobj.getBoolean("muting")); } catch (Exception ignored) { relationship.setMuting(false); } try { relationship.setMuting_notifications(!resobj.getBoolean("notifications_enabled")); } catch (Exception ignored) { relationship.setMuting_notifications(false); } relationship.setEndorsed(false); relationship.setShowing_reblogs(true); relationship.setRequested(false); } catch (JSONException e) { setDefaultError(e); } return relationship; } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return relationship; } /** * Returns a relationship between the authenticated account and an account * * @param accounts ArrayList accounts fetched * @return Relationship entity */ public APIResponse getRelationship(List accounts) { HashMap params = new HashMap<>(); if (accounts != null && accounts.size() > 0) { StringBuilder parameters = new StringBuilder(); for (Account account : accounts) parameters.append("target_id[]=").append(account.getId()).append("&"); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(12)); params.put("target_id[]", parameters.toString()); List relationships = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/friendships/show.json"), 60, params, prefKeyOauthTokenT); relationships = parseRelationshipResponse(new JSONArray(response)); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setRelationships(relationships); } return apiResponse; } /** * Retrieves status for the account *synchronously* * * @param accountId String Id of the account * @return APIResponse */ public APIResponse getStatus(String accountId) { return getStatus(accountId, false, null, null, tootPerPage); } /** * Retrieves status for the account *synchronously* * * @param accountId String Id of the account * @param max_id String id max * @return APIResponse */ public APIResponse getStatus(String accountId, String max_id) { return getStatus(accountId, false, max_id, null, tootPerPage); } /** * Retrieves status with media for the account *synchronously* * * @param accountId String Id of the account * @param max_id String id max * @return APIResponse */ public APIResponse getStatusWithMedia(String accountId, String max_id) { return getStatus(accountId, false, max_id, null, tootPerPage); } /** * Retrieves pinned status(es) *synchronously* * * @param accountId String Id of the account * @param max_id String id max * @return APIResponse */ public APIResponse getPinnedStatuses(String accountId, String max_id) { return getStatus(accountId, false, max_id, null, tootPerPage); } /** * Retrieves replies status(es) *synchronously* * * @param accountId String Id of the account * @param max_id String id max * @return APIResponse */ public APIResponse getAccountTLStatuses(String accountId, String max_id, boolean exclude_replies) { return getStatus(accountId, exclude_replies, max_id, null, tootPerPage); } /** * Retrieves status for the account *synchronously* * * @param accountId String Id of the account * @param exclude_replies boolean excludes replies * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getStatus(String accountId, boolean exclude_replies, String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); //noinspection ConstantConditions if (0 < limit || limit > 40) limit = 40; params.put("user_id", accountId); params.put("exclude_replies", Boolean.toString(exclude_replies)); params.put("count", String.valueOf(limit)); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/statuses/user_timeline.json"), 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } public APIResponse getCustomArtTimelineSinceId(boolean local, String tag, String since_id, List any, List all, List none) { return getArtTimeline(local, tag, null, since_id, any, all, none); } /** * Retrieves art timeline * * @param local boolean only local timeline * @param max_id String id max * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getArtTimeline(boolean local, String tag, String max_id, String since_id, List any, List all, List none) { if (tag == null) tag = "mastoart"; APIResponse apiResponse = getPublicTimelineTag(tag, local, true, max_id, since_id, tootPerPage, any, all, none); APIResponse apiResponseReply = new APIResponse(); if (apiResponse != null) { apiResponseReply.setMax_id(apiResponse.getMax_id()); apiResponseReply.setSince_id(apiResponse.getSince_id()); apiResponseReply.setStatuses(new ArrayList<>()); if (apiResponse.getStatuses() != null && apiResponse.getStatuses().size() > 0) { for (Status status : apiResponse.getStatuses()) { if (status.getMedia_attachments() != null) { String statusSerialized = Helper.statusToStringStorage(status); for (Attachment attachment : status.getMedia_attachments()) { Status newStatus = Helper.restoreStatusFromString(statusSerialized); if (newStatus == null) break; newStatus.setArt_attachment(attachment); apiResponseReply.getStatuses().add(newStatus); } } } } } return apiResponseReply; } /** * Retrieves accounts that reblogged the status *synchronously* * * @param statusId String Id of the status * @param max_id String id max * @return APIResponse */ @SuppressWarnings("SameParameterValue") public APIResponse getRebloggedBy(String statusId, String max_id) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); params.put("limit", "80"); accounts = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl(String.format("/statuses/%s/reblogged_by", statusId)), 60, params, prefKeyOauthTokenT); accounts = parseAccountResponse(new JSONArray(response)); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setAccounts(accounts); return apiResponse; } /** * Retrieves accounts that favourited the status *synchronously* * * @param statusId String Id of the status * @param max_id String id max * @return APIResponse */ @SuppressWarnings("SameParameterValue") public APIResponse getFavouritedBy(String statusId, String max_id) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); params.put("limit", "80"); accounts = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl(String.format("/statuses/%s/favourited_by", statusId)), 60, params, prefKeyOauthTokenT); accounts = parseAccountResponse(new JSONArray(response)); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setAccounts(accounts); return apiResponse; } /** * Retrieves the context of status with replies *synchronously* * * @param statusId Id of the status * @return List */ public app.fedilab.android.client.Entities.Context getStatusContext(String statusId, boolean directtimeline) { app.fedilab.android.client.Entities.Context statusContext = new app.fedilab.android.client.Entities.Context(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response; if (!directtimeline) response = httpsConnection.get(getAbsoluteUrl(String.format("/statusnet/conversation/%s.json", statusId)), 60, null, prefKeyOauthTokenT); else { HashMap params = new HashMap<>(); params.put("uri", statusId); response = httpsConnection.get(getAbsoluteUrl("/direct_messages/conversation.json"), 60, params, prefKeyOauthTokenT); } statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { ArrayList descendants = new ArrayList<>(); statusContext.setAncestors(statuses); statusContext.setDescendants(descendants); } } catch (HttpsConnection.HttpsConnectionException e) { if (e.getStatusCode() != 404 && e.getStatusCode() != 501) setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | KeyManagementException | IOException | JSONException e) { e.printStackTrace(); } return statusContext; } /** * Retrieves direct timeline for the account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getDirectTimeline(String max_id) { return getDirectTimeline(max_id, null, tootPerPage); } /** * Retrieves direct timeline for the account *synchronously* * * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getDirectTimeline(String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 80) limit = 80; params.put("count", String.valueOf(limit)); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/direct_messages.json"), 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Retrieves home timeline for the account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getHomeTimeline(String max_id) { return getHomeTimeline(max_id, null, null); } /** * Retrieves home timeline for the account since an Id value *synchronously* * * @return APIResponse */ public APIResponse getHomeTimelineSinceId(String since_id) { return getHomeTimeline(null, since_id, null); } /** * Retrieves home timeline for the account *synchronously* * * @param max_id String id max * @param since_id String since the id * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getHomeTimeline(String max_id, String since_id, String min_id) { apiResponse = new APIResponse(); HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (min_id != null) params.put("min_id", min_id); //Current user statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/statuses/home_timeline.json"), 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Retrieves public timeline for the account *synchronously* * * @param local boolean only local timeline * @param max_id String id max * @return APIResponse */ public APIResponse getPublicTimeline(boolean local, String max_id) { return getPublicTimeline(local, max_id, null, tootPerPage); } /** * Retrieves public timeline for the account since an Id value *synchronously* * * @param local boolean only local timeline * @param since_id String id since * @return APIResponse */ public APIResponse getPublicTimelineSinceId(boolean local, String since_id) { return getPublicTimeline(local, null, since_id, tootPerPage); } /** * Retrieves public timeline for the account *synchronously* * * @param local boolean only local timeline * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getPublicTimeline(boolean local, String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); if (local) params.put("local", Boolean.toString(true)); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 40) limit = 40; params.put("count", String.valueOf(limit)); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String url; if (local) url = getAbsoluteUrl("/statuses/public_timeline.json"); else url = getAbsoluteUrl("/statuses/public_and_external_timeline.json"); String response = httpsConnection.get(url, 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Retrieves public tag timeline *synchronously* * * @param tag String * @param local boolean only local timeline * @param max_id String id max * @return APIResponse */ @SuppressWarnings("SameParameterValue") public APIResponse getPublicTimelineTag(String tag, boolean local, String max_id, List any, List all, List none) { return getPublicTimelineTag(tag, local, false, max_id, null, tootPerPage, any, all, none); } /** * Retrieves public tag timeline *synchronously* * * @param tag String * @param local boolean only local timeline * @param since_id String since id * @return APIResponse */ @SuppressWarnings("SameParameterValue") public APIResponse getPublicTimelineTagSinceId(String tag, boolean local, String since_id, List any, List all, List none) { return getPublicTimelineTag(tag, local, false, null, since_id, tootPerPage, any, all, none); } /** * Retrieves public tag timeline *synchronously* * * @param tag String * @param local boolean only local timeline * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getPublicTimelineTag(String tag, boolean local, boolean onlymedia, String max_id, String since_id, int limit, List any, List all, List none) { HashMap params = new HashMap<>(); if (local) params.put("local", Boolean.toString(true)); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 40) limit = 40; if (onlymedia) params.put("only_media", Boolean.toString(true)); if (any != null && any.size() > 0) { StringBuilder parameters = new StringBuilder(); for (String a : any) parameters.append("any[]=").append(a).append("&"); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(6)); params.put("any[]", parameters.toString()); } if (all != null && all.size() > 0) { StringBuilder parameters = new StringBuilder(); for (String a : all) parameters.append("all[]=").append(a).append("&"); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(6)); params.put("all[]", parameters.toString()); } if (none != null && none.size() > 0) { StringBuilder parameters = new StringBuilder(); for (String a : none) parameters.append("none[]=").append(a).append("&"); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1).substring(7)); params.put("none[]", parameters.toString()); } params.put("limit", String.valueOf(limit)); statuses = new ArrayList<>(); if (tag == null) return null; try { String query = tag.trim(); HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); if (MainActivity.social != UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE) try { query = URLEncoder.encode(query, "UTF-8"); } catch (UnsupportedEncodingException ignored) { } String response = httpsConnection.get(getAbsoluteUrl(String.format("/timelines/tag/%s", query)), 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Retrieves muted users by the authenticated account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getMuted(String max_id) { return getAccounts("/mutes/users/list.json", null, max_id, null, accountPerPage); } /** * Retrieves blocked users by the authenticated account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getBlocks(String max_id) { return getAccounts("/blocks/list.json", null, max_id, null, accountPerPage); } /** * Retrieves following for the account specified by targetedId *synchronously* * * @param targetedId String targetedId * @param max_id String id max * @return APIResponse */ public APIResponse getFollowing(String targetedId, String max_id) { return getAccounts("/statuses/friends.json", targetedId, max_id, null, accountPerPage); } /** * Retrieves followers for the account specified by targetedId *synchronously* * * @param targetedId String targetedId * @param max_id String id max * @return APIResponse */ public APIResponse getFollowers(String targetedId, String max_id) { return getAccounts("/statuses/followers.json", targetedId, max_id, null, accountPerPage); } /** * Retrieves blocked users by the authenticated account *synchronously* * * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getAccounts(String action, String targetedId, String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 40) limit = 40; params.put("limit", String.valueOf(limit)); if (targetedId != null) params.put("user_id", targetedId); accounts = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); accounts = parseAccountResponse(new JSONArray(response)); if (accounts.size() == 1) { if (accounts.get(0).getAcct() == null) { Throwable error = new Throwable(context.getString(R.string.toast_error)); setError(500, error); } } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setAccounts(accounts); return apiResponse; } /** * Retrieves favourited status for the authenticated account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getFavourites(String max_id) { return getFavourites(max_id, null, tootPerPage); } /** * Retrieves favourited status for the authenticated account *synchronously* * * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getFavourites(String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 40) limit = 40; params.put("count", String.valueOf(limit)); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/favorites.json"), 60, params, prefKeyOauthTokenT); statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Makes the post action for a status * * @param statusAction Enum * @param targetedId String id of the targeted Id *can be this of a status or an account* * @return in status code - Should be equal to 200 when action is done */ public int postAction(API.StatusAction statusAction, String targetedId) { return postAction(statusAction, targetedId, null); } /** * Makes the post action for a status * * @param targetedId String id of the targeted Id *can be this of a status or an account* * @param muteNotifications - boolean - notifications should be also muted * @return in status code - Should be equal to 200 when action is done */ public int muteNotifications(String targetedId, boolean muteNotifications) { HashMap params = new HashMap<>(); params.put("notifications", Boolean.toString(muteNotifications)); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); httpsConnection.post(getAbsoluteUrl(String.format("/accounts/%s/mute", targetedId)), 60, params, prefKeyOauthTokenT); actionCode = httpsConnection.getActionCode(); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { e.printStackTrace(); } return actionCode; } /** * Makes the post action * * @param status Status object related to the status * @return in status code - Should be equal to 200 when action is done */ public int reportAction(Status status) { return postAction(API.StatusAction.REPORT, null, status); } public int statusAction(Status status) { return postAction(API.StatusAction.CREATESTATUS, null, status); } /** * Makes the post action * * @param statusAction Enum * @param targetedId String id of the targeted Id *can be this of a status or an account* * @param status Status object related to the status * @return in status code - Should be equal to 200 when action is done */ private int postAction(API.StatusAction statusAction, String targetedId, Status status) { String action; HashMap params = null; switch (statusAction) { case FAVOURITE: if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.GNU) { action = "/favorites/create.json"; } else { action = "/friendica/activity/like.json"; } params = new HashMap<>(); params.put("id", targetedId); break; case UNFAVOURITE: if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.GNU) { action = "/favorites/destroy.json"; } else { action = "/friendica/activity/unlike.json"; } params = new HashMap<>(); params.put("id", targetedId); break; case REBLOG: action = String.format("/statuses/retweet/%s.json", targetedId); break; case UNREBLOG: action = String.format("/statuses/unretweet/%s.json", targetedId); break; case FOLLOW: action = "/friendships/create.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case REMOTE_FOLLOW: action = "/follows"; params = new HashMap<>(); params.put("uri", targetedId); break; case UNFOLLOW: action = "/friendships/destroy.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case BLOCK: action = "/blocks/create.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case UNBLOCK: action = "/blocks/destroy.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case MUTE: action = "/mutes/users/create.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case UNMUTE: action = "/mutes/users/destroy.json"; params = new HashMap<>(); params.put("user_id", targetedId); break; case UNSTATUS: if (!status.getVisibility().equals("direct")) action = String.format("/statuses/destroy/%s.json", targetedId); else { action = "/direct_messages/destroy.json"; params = new HashMap<>(); params.put("id", targetedId); } break; case CREATESTATUS: params = new HashMap<>(); if (!status.getVisibility().equals("direct")) action = "/statuses/update.json"; else action = "/direct_messages/new.json"; if (!status.getVisibility().equals("direct")) { try { params.put("status", URLEncoder.encode(status.getContent(), "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("status", status.getContent()); } } else { try { params.put("text", URLEncoder.encode(status.getContent(), "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("text", status.getContent()); } } if (status.getContentType() != null) params.put("content_type", status.getContentType()); if (status.getIn_reply_to_id() != null) { if (!status.getVisibility().equals("direct")) params.put("in_reply_to_status_id", status.getIn_reply_to_id()); else params.put("replyto", status.getConversationId()); } if (status.getMedia_attachments() != null && status.getMedia_attachments().size() > 0) { StringBuilder parameters = new StringBuilder(); for (Attachment attachment : status.getMedia_attachments()) parameters.append(attachment.getId()).append(","); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1)); params.put("media_ids", parameters.toString()); } if (status.isSensitive()) params.put("possibly_sensitive", Boolean.toString(status.isSensitive())); break; default: return -1; } try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String resp = httpsConnection.post(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT); actionCode = httpsConnection.getActionCode(); if (statusAction == API.StatusAction.REBLOG || statusAction == API.StatusAction.UNREBLOG || statusAction == API.StatusAction.FAVOURITE || statusAction == API.StatusAction.UNFAVOURITE) { Bundle b = new Bundle(); try { Status status1 = parseStatuses(context, new JSONObject(resp)); b.putParcelable("status", status1); } catch (JSONException ignored) { } Intent intentBC = new Intent(Helper.RECEIVE_ACTION); intentBC.putExtras(b); LocalBroadcastManager.getInstance(context).sendBroadcast(intentBC); SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); Account account = new AccountDAO(context, db).getAccountByToken(prefKeyOauthTokenT); new TimelineCacheDAO(context, db).update(targetedId, resp, account.getId(), account.getToken()); } else if (statusAction == API.StatusAction.UNSTATUS) { SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); new TimelineCacheDAO(context, db).remove(targetedId); } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException e) { e.printStackTrace(); } return actionCode; } /** * Posts a status * * @param status Status object related to the status * @return APIResponse */ public APIResponse postStatusAction(Status status) { HashMap params = new HashMap<>(); if (status.getContentType() != null) params.put("content_type", status.getContentType()); if (!status.getVisibility().equals("direct")) { try { params.put("status", URLEncoder.encode(status.getContent(), "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("status", status.getContent()); } } else { try { params.put("text", URLEncoder.encode(status.getContent(), "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("text", status.getContent()); } SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); //Current user String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); Account currentAccount = new AccountDAO(context, db).getUniqAccount(userId, Helper.getLiveInstance(context)); params.put("user_id", currentAccount.getId()); params.put("screen_name", currentAccount.getAcct()); } if (status.getIn_reply_to_id() != null) if (!status.getVisibility().equals("direct")) params.put("in_reply_to_status_id", status.getIn_reply_to_id()); else params.put("replyto", status.getIn_reply_to_id()); if (status.getMedia_attachments() != null && status.getMedia_attachments().size() > 0) { StringBuilder parameters = new StringBuilder(); for (Attachment attachment : status.getMedia_attachments()) parameters.append(attachment.getId()).append(","); parameters = new StringBuilder(parameters.substring(0, parameters.length() - 1)); params.put("media_ids", parameters.toString()); } if (status.isSensitive()) params.put("possibly_sensitive", Boolean.toString(status.isSensitive())); statuses = new ArrayList<>(); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response; if (!status.getVisibility().equals("direct")) response = httpsConnection.post(getAbsoluteUrl("/statuses/update.json"), 60, params, prefKeyOauthTokenT); else response = httpsConnection.post(getAbsoluteUrl("/direct_messages/new.json"), 60, params, prefKeyOauthTokenT); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); Status statusreturned = parseStatuses(context, new JSONObject(response)); statuses.add(statusreturned); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setStatuses(statuses); return apiResponse; } /** * Retrieves notifications for the authenticated account since an id*synchronously* * * @param since_id String since max * @return APIResponse */ public APIResponse getNotificationsSince(DisplayNotificationsFragment.Type type, String since_id) { return getNotifications(type, null, since_id, notificationPerPage); } /** * Retrieves notifications for the authenticated account *synchronously* * * @param max_id String id max * @return APIResponse */ public APIResponse getNotifications(DisplayNotificationsFragment.Type type, String max_id) { return getNotifications(type, max_id, null, notificationPerPage); } /** * Retrieves notifications for the authenticated account *synchronously* * * @param max_id String id max * @param since_id String since the id * @param limit int limit - max value 40 * @return APIResponse */ @SuppressWarnings("SameParameterValue") private APIResponse getNotifications(DisplayNotificationsFragment.Type type, String max_id, String since_id, int limit) { HashMap params = new HashMap<>(); String stringType = null; if (max_id != null) params.put("max_id", max_id); if (since_id != null) params.put("since_id", since_id); if (0 > limit || limit > 30) limit = 30; params.put("count", String.valueOf(limit)); List notifications = new ArrayList<>(); String url = null; SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); //Current user SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); String userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); String instance = sharedpreferences.getString(Helper.PREF_INSTANCE, Helper.getLiveInstance(context)); Account account = new AccountDAO(context, db).getUniqAccount(userId, instance); if (type == DisplayNotificationsFragment.Type.MENTION) { params.put("name", account.getAcct()); url = getAbsoluteUrl("/statuses/mentions_timeline.json"); stringType = "mention"; } else if (type == DisplayNotificationsFragment.Type.BOOST) { url = getAbsoluteUrl("/statuses/retweets_of_me.json"); stringType = "reblog"; } else if (type == DisplayNotificationsFragment.Type.FOLLOW) { url = getAbsoluteUrl("/statuses/followers.json"); stringType = "follow"; } if (url == null) { Error error = new Error(); error.setStatusCode(500); error.setError(context.getString(R.string.toast_error)); apiResponse.setError(error); return apiResponse; } try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(url, 60, params, prefKeyOauthTokenT); apiResponse.setSince_id(httpsConnection.getSince_id()); apiResponse.setMax_id(httpsConnection.getMax_id()); if (type == DisplayNotificationsFragment.Type.FOLLOW) { List accounts = parseAccountResponse(new JSONArray(response)); for (Account st : accounts) { Notification notification = new Notification(); notification.setType(stringType); notification.setId(st.getId()); notification.setStatus(null); notification.setAccount(st); notifications.add(notification); } } else { List statuses = parseStatuses(context, new JSONArray(response)); for (Status st : statuses) { Notification notification = new Notification(); notification.setType(stringType); notification.setId(st.getId()); Status.fillSpan(new WeakReference<>(context), st); notification.setStatus(st); notification.setAccount(st.getAccount()); notifications.add(notification); } } } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } apiResponse.setNotifications(notifications); return apiResponse; } /** * Retrieves Accounts and feeds when searching *synchronously* * * @param query String search * @return Results */ public APIResponse searchRemote(String instance, String query, String max_id) { HashMap params = new HashMap<>(); try { query = URLEncoder.encode(query, "UTF-8"); } catch (UnsupportedEncodingException ignored) { } if (max_id != null) params.put("max_id", max_id); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteRemoteUrl(instance, "/statusnet/tags/timeline/" + query.trim().toLowerCase().replaceAll("#", "") + ".json"), 60, params, null); List statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } apiResponse.setStatuses(statuses); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | KeyManagementException | JSONException | IOException e) { e.printStackTrace(); } return apiResponse; } /** * Retrieves Accounts and feeds when searching *synchronously* * * @param query String search * @return Results */ public APIResponse search(String query) { Results results = new Results(); HashMap params = new HashMap<>(); apiResponse = new APIResponse(); if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE) params.put("q", query); else try { params.put("q", URLEncoder.encode(query, "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("q", query); } try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/users/search.json"), 60, params, prefKeyOauthTokenT); List accounts = parseAccountResponse(new JSONArray(response)); results.setAccounts(accounts); apiResponse.setResults(results); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return apiResponse; } /** * Retrieves Accounts and feeds when searching *synchronously* * * @param query String search * @return Results */ public APIResponse search2(String query) { Results results = new Results(); HashMap params = new HashMap<>(); apiResponse = new APIResponse(); if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE) params.put("q", query); else try { params.put("q", URLEncoder.encode(query, "UTF-8")); } catch (UnsupportedEncodingException e) { params.put("q", query); } try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/search.json"), 60, params, prefKeyOauthTokenT); List statuses = parseStatuses(context, new JSONArray(response)); results.setStatuses(statuses); apiResponse.setResults(results); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return apiResponse; } /** * Retrieves Accounts and feeds when searching *synchronously* * * @param query String search * @return Results */ public APIResponse search(String query, String max_id) { HashMap params = new HashMap<>(); try { query = URLEncoder.encode(query, "UTF-8"); } catch (UnsupportedEncodingException ignored) { } if (max_id != null) params.put("max_id", max_id); try { HttpsConnection httpsConnection = new HttpsConnection(context, this.instance); String response = httpsConnection.get(getAbsoluteUrl("/statusnet/tags/timeline/" + query.trim().toLowerCase().replaceAll("#", "") + ".json"), 60, params, null); List statuses = parseStatuses(context, new JSONArray(response)); if (statuses.size() > 0) { apiResponse.setSince_id(statuses.get(0).getId()); apiResponse.setMax_id(statuses.get(statuses.size() - 1).getId()); } apiResponse.setStatuses(statuses); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); e.printStackTrace(); } catch (NoSuchAlgorithmException | IOException | KeyManagementException | JSONException e) { e.printStackTrace(); } return apiResponse; } /** * Parse json response for list of accounts * * @param jsonArray JSONArray * @return List */ private List parseAccountResponse(JSONArray jsonArray) { List accounts = new ArrayList<>(); try { int i = 0; while (i < jsonArray.length()) { JSONObject resobj = jsonArray.getJSONObject(i); Account account = parseAccountResponse(resobj); accounts.add(account); i++; } } catch (JSONException e) { setDefaultError(e); } return accounts; } /** * Parse json response an unique relationship * * @param resobjIni JSONObject * @return Relationship */ private Relationship parseRelationshipResponse(JSONObject resobjIni) { Relationship relationship = new Relationship(); try { JSONObject resobj = resobjIni.getJSONObject("relationship").getJSONObject("source"); relationship.setId(resobj.get("id").toString()); relationship.setFollowing(resobj.getBoolean("following")); relationship.setFollowed_by(resobj.getBoolean("followed_by")); relationship.setBlocking(resobj.getBoolean("blocking")); try { relationship.setMuting(resobj.getBoolean("muting")); } catch (Exception ignored) { relationship.setMuting(false); } try { relationship.setMuting_notifications(!resobj.getBoolean("notifications_enabled")); } catch (Exception ignored) { relationship.setMuting_notifications(false); } relationship.setEndorsed(false); relationship.setShowing_reblogs(true); relationship.setRequested(false); } catch (JSONException e) { setDefaultError(e); } return relationship; } /** * Parse json response for list of relationship * * @param jsonArray JSONArray * @return List */ private List parseRelationshipResponse(JSONArray jsonArray) { List relationships = new ArrayList<>(); try { int i = 0; while (i < jsonArray.length()) { JSONObject resobj = jsonArray.getJSONObject(i); Relationship relationship = parseRelationshipResponse(resobj); relationships.add(relationship); i++; } } catch (JSONException e) { setDefaultError(e); } return relationships; } /** * Set the error message * * @param statusCode int code * @param error Throwable error */ private void setError(int statusCode, Throwable error) { APIError = new Error(); APIError.setStatusCode(statusCode); String message = statusCode + " - " + error.getMessage(); try { JSONObject jsonObject = new JSONObject(Objects.requireNonNull(error.getMessage())); String errorM = jsonObject.get("error").toString(); message = "Error " + statusCode + " : " + errorM; } catch (JSONException e) { if (error.getMessage().split(".").length > 0) { String errorM = error.getMessage().split(".")[0]; message = "Error " + statusCode + " : " + errorM; } } APIError.setError(message); apiResponse.setError(APIError); } private void setDefaultError(Exception e) { APIError = new Error(); if (e.getLocalizedMessage() != null && e.getLocalizedMessage().trim().length() > 0) APIError.setError(e.getLocalizedMessage()); else if (e.getMessage() != null && e.getMessage().trim().length() > 0) APIError.setError(e.getMessage()); else APIError.setError(context.getString(R.string.toast_error)); apiResponse.setError(APIError); } public Error getError() { return APIError; } private String getAbsoluteUrl(String action) { return Helper.instanceWithProtocol(this.context, this.instance) + "/api" + action; } private String getAbsoluteRemoteUrl(String instance, String action) { return Helper.instanceWithProtocol(this.context, instance) + "/api" + action; } }