aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--docs/MISSION.md25
-rw-r--r--res/layout/join_conference_dialog.xml3
-rw-r--r--res/menu/conference_context.xml11
-rw-r--r--res/values/strings.xml1
-rw-r--r--src/eu/siacs/conversations/entities/Account.java12
-rw-r--r--src/eu/siacs/conversations/entities/Bookmark.java94
-rw-r--r--src/eu/siacs/conversations/entities/Conversation.java6
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java53
-rw-r--r--src/eu/siacs/conversations/ui/StartConversation.java91
10 files changed, 280 insertions, 18 deletions
diff --git a/README.md b/README.md
index c6c26cea..53af9d6c 100644
--- a/README.md
+++ b/README.md
@@ -127,7 +127,7 @@ longer necessary. Using priorities to route OTR messages isn't pratical either
because they are not changeable on the fly. Metrics like last active client
(the client which sent the last message) are much better.
-Unfortunatly these modern replacement for lagecay XMPP featurs are not widely
+Unfortunatly these modern replacement for legacy XMPP featurs are not widely
adopted. However Conversations should be an instant messanger for the future and
instead of making Conversations compatible with the past we should work on
implementing new, improved technologies into other XMPP clients as well.
diff --git a/docs/MISSION.md b/docs/MISSION.md
new file mode 100644
index 00000000..269ea85b
--- /dev/null
+++ b/docs/MISSION.md
@@ -0,0 +1,25 @@
+Conversations is a messanger for the next decade. Based on already established
+internet standards that have been around for over ten years Coversations isn’t
+trying to replace current commercial messangers. It will simply outlive them.
+Commercial, closed source products are coming and going. 15 years ago we had
+ICQ which was replaced by Skype. MySpace was replaced by Facebook. WhatsApp and
+Hangouts will disapear soon. Internet standards however stick around. People are
+still using IRC and e-mail even though these protocols have been around for
+decades. Utilizing proven standards doesn’t mean one can not evolve. GMail has
+revolutionized the way we look at e-mail. Firefox and Chrome have changed the
+way we use the Web. Conversations will change the way we look at instant
+messaging. Being less obstrusive than a telephone call instant messaging has
+always played an importent role in modern society. Conversations will show that
+instant messaging can be fast, relialbe and private. Conversations will not
+force its security and privacey aspects upon the user. For those willing to use encryption
+Conversations will make it as uncomplicated as possible. However Conversations
+is aware that end-to-end encryption by the very principle isn’t trivial. Instead
+of trying the impossible and making encryption easier than comparing a
+fingerprint Conversations will try to educate the willing user and explain the
+necessary steps and the reasons behind them. Those unwilling to learn about
+encryption will still be protected by the design principals of Conversations.
+Conversations will simply not share or generate certain information for example
+by encouraging the use of federated servers. Conversations will always
+utilize the best available standards for encryption and media encoding instead
+of reinventing the wheel. However it isn’t afraid to break with behavior patterns
+that have been proven ineffctive.
diff --git a/res/layout/join_conference_dialog.xml b/res/layout/join_conference_dialog.xml
index 2a0e300a..431bf59e 100644
--- a/res/layout/join_conference_dialog.xml
+++ b/res/layout/join_conference_dialog.xml
@@ -41,6 +41,7 @@
android:layout_marginTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/save_as_bookmark" />
+ android:text="@string/save_as_bookmark"
+ android:checked="true" />
</LinearLayout>
diff --git a/res/menu/conference_context.xml b/res/menu/conference_context.xml
new file mode 100644
index 00000000..fd898580
--- /dev/null
+++ b/res/menu/conference_context.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/context_join_conference"
+ android:title="@string/join_conference"/>
+ <item
+ android:id="@+id/context_delete_conference"
+ android:title="@string/delete_bookmark"/>
+
+</menu> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 417d838e..9308bba1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -267,4 +267,5 @@
<string name="conference_address">Conference address</string>
<string name="conference_address_example">room@conference.example.com</string>
<string name="save_as_bookmark">Save as bookmark</string>
+ <string name="delete_bookmark">Delete bookmark</string>
</resources> \ No newline at end of file
diff --git a/src/eu/siacs/conversations/entities/Account.java b/src/eu/siacs/conversations/entities/Account.java
index a73d49f9..20abddcd 100644
--- a/src/eu/siacs/conversations/entities/Account.java
+++ b/src/eu/siacs/conversations/entities/Account.java
@@ -1,6 +1,8 @@
package eu.siacs.conversations.entities;
import java.security.interfaces.DSAPublicKey;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
@@ -67,6 +69,8 @@ public class Account extends AbstractEntity{
private String otrFingerprint;
private Roster roster = null;
+
+ private List<Bookmark> bookmarks = new ArrayList<Bookmark>();
public Account() {
this.uuid = "0";
@@ -297,4 +301,12 @@ public class Account extends AbstractEntity{
}
return this.roster;
}
+
+ public void setBookmarks(List<Bookmark> bookmarks) {
+ this.bookmarks = bookmarks;
+ }
+
+ public List<Bookmark> getBookmarks() {
+ return this.bookmarks;
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Bookmark.java b/src/eu/siacs/conversations/entities/Bookmark.java
new file mode 100644
index 00000000..1b97c573
--- /dev/null
+++ b/src/eu/siacs/conversations/entities/Bookmark.java
@@ -0,0 +1,94 @@
+package eu.siacs.conversations.entities;
+
+import java.util.Locale;
+
+import eu.siacs.conversations.xml.Element;
+
+public class Bookmark implements ListItem {
+
+ private Account account;
+ private String jid;
+ private String nick;
+ private String displayName;
+ private boolean autojoin;
+
+ public Bookmark(Account account) {
+ this.account = account;
+ }
+
+ public static Bookmark parse(Element element, Account account) {
+ Bookmark bookmark = new Bookmark(account);
+ bookmark.setJid(element.getAttribute("jid"));
+ bookmark.setDisplayName(element.getAttribute("name"));
+ String autojoin = element.getAttribute("autojoin");
+ if (autojoin!=null && (autojoin.equals("true")||autojoin.equals("1"))) {
+ bookmark.setAutojoin(true);
+ } else {
+ bookmark.setAutojoin(false);
+ }
+ Element nick = element.findChild("nick");
+ if (nick!=null) {
+ bookmark.setNick(nick.getContent());
+ }
+ return bookmark;
+ }
+
+ public void setAutojoin(boolean autojoin) {
+ this.autojoin = autojoin;
+ }
+
+ public void setDisplayName(String name) {
+ this.displayName = name;
+ }
+
+ public void setJid(String jid) {
+ this.jid = jid;
+ }
+
+ public void setNick(String nick) {
+ this.nick = nick;
+ }
+
+ @Override
+ public int compareTo(ListItem another) {
+ return this.getDisplayName().compareToIgnoreCase(another.getDisplayName());
+ }
+
+ @Override
+ public String getDisplayName() {
+ if (displayName!=null) {
+ return displayName;
+ } else {
+ return this.jid.split("@")[0];
+ }
+ }
+
+ @Override
+ public String getJid() {
+ return this.jid.toLowerCase(Locale.US);
+ }
+
+ public String getNick() {
+ return this.nick;
+ }
+
+ public boolean autojoin() {
+ return autojoin;
+ }
+
+ @Override
+ public String getProfilePhoto() {
+ return null;
+ }
+
+ public boolean match(String needle) {
+ return needle == null
+ || getJid().contains(needle.toLowerCase(Locale.US))
+ || getDisplayName().toLowerCase(Locale.US)
+ .contains(needle.toLowerCase(Locale.US));
+ }
+
+ public Account getAccount() {
+ return this.account;
+ }
+}
diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java
index 23ab382f..fbd87f3f 100644
--- a/src/eu/siacs/conversations/entities/Conversation.java
+++ b/src/eu/siacs/conversations/entities/Conversation.java
@@ -64,6 +64,8 @@ public class Conversation extends AbstractEntity {
private boolean otrSessionNeedsStarting = false;
+ private Bookmark bookmark;
+
public Conversation(String name, Account account, String contactJid,
int mode) {
this(java.util.UUID.randomUUID().toString(), name, null, account
@@ -375,4 +377,8 @@ public class Conversation extends AbstractEntity {
public byte[] getSymmetricKey() {
return this.symmetricKey;
}
+
+ public void setBookmark(Bookmark bookmark) {
+ this.bookmark = bookmark;
+ }
}
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index 0f90f725..3fa263ab 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -20,6 +20,7 @@ import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
@@ -245,9 +246,13 @@ public class XmppConnectionService extends Service {
return message;
}
- public Conversation findMuc(String name, Account account) {
+ public Conversation findMuc(Bookmark bookmark) {
+ return findMuc(bookmark.getJid(), bookmark.getAccount());
+ }
+
+ public Conversation findMuc(String jid, Account account) {
for (Conversation conversation : this.conversations) {
- if (conversation.getContactJid().split("/")[0].equals(name)
+ if (conversation.getContactJid().split("/")[0].equals(jid)
&& (conversation.getAccount() == account)) {
return conversation;
}
@@ -466,6 +471,7 @@ public class XmppConnectionService extends Service {
account.getRoster().clearPresences();
account.clearPresences(); // self presences
fetchRosterFromServer(account);
+ fetchBookmarks(account);
sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
connectMultiModeConversations(account);
updateConversationUi();
@@ -660,6 +666,45 @@ public class XmppConnectionService extends Service {
}
});
}
+
+ public void fetchBookmarks(Account account) {
+ IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
+ Element query = iqPacket.query("jabber:iq:private");
+ query.addChild("storage", "storage:bookmarks");
+ OnIqPacketReceived callback = new OnIqPacketReceived() {
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ Element query = packet.query();
+ List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ Element storage = query.findChild("storage", "storage:bookmarks");
+ if (storage!=null) {
+ for(Element item : storage.getChildren()) {
+ if (item.getName().equals("conference")) {
+ Log.d(LOGTAG,item.toString());
+ Bookmark bookmark = Bookmark.parse(item,account);
+ bookmarks.add(bookmark);
+ if (bookmark.autojoin()) {
+ Log.d(LOGTAG,"has autojoin");
+ Conversation conversation = findMuc(bookmark);
+ if (conversation!=null) {
+ Log.d(LOGTAG,"conversation existed. adding bookmark");
+ conversation.setBookmark(bookmark);
+ } else {
+ Log.d(LOGTAG,"creating new conversation");
+ conversation = findOrCreateConversation(account, bookmark.getJid(), true);
+ conversation.setBookmark(bookmark);
+ }
+ }
+ }
+ }
+ }
+ account.setBookmarks(bookmarks);
+ }
+ };
+ sendIqPacket(account, iqPacket, callback);
+
+ }
private void mergePhoneContactsWithRoster() {
PhoneHelper.loadPhoneContacts(getApplicationContext(),
@@ -1297,6 +1342,10 @@ public class XmppConnectionService extends Service {
account.getXmppConnection().sendPresencePacket(packet);
}
+ public void sendIqPacket(Account account, IqPacket packet, OnIqPacketReceived callback) {
+ account.getXmppConnection().sendIqPacket(packet, callback);
+ }
+
public MessageGenerator getMessageGenerator() {
return this.mMessageGenerator;
}
diff --git a/src/eu/siacs/conversations/ui/StartConversation.java b/src/eu/siacs/conversations/ui/StartConversation.java
index b37d2d07..99b3385c 100644
--- a/src/eu/siacs/conversations/ui/StartConversation.java
+++ b/src/eu/siacs/conversations/ui/StartConversation.java
@@ -37,6 +37,7 @@ import android.widget.Spinner;
import android.widget.TextView;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
+import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem;
@@ -63,6 +64,9 @@ public class StartConversation extends XmppActivity {
private List<String> mKnownConferenceHosts;
private EditText mSearchEditText;
+
+ public int conference_context_id;
+ public int contact_context_id;
private TabListener mTabListener = new TabListener() {
@@ -115,7 +119,7 @@ public class StartConversation extends XmppActivity {
imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(),
InputMethodManager.HIDE_IMPLICIT_ONLY);
mSearchEditText.setText("");
- filterContacts(null);
+ filter(null);
return true;
}
};
@@ -123,7 +127,7 @@ public class StartConversation extends XmppActivity {
@Override
public void afterTextChanged(Editable editable) {
- filterContacts(editable.toString());
+ filter(editable.toString());
}
@Override
@@ -172,9 +176,19 @@ public class StartConversation extends XmppActivity {
mConferenceAdapter = new ListItemAdapter(conferences);
mConferenceListFragment.setListAdapter(mConferenceAdapter);
+ mConferenceListFragment.setContextMenu(R.menu.conference_context);
+ mConferenceListFragment.setOnListItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> arg0, View arg1,
+ int position, long arg3) {
+ openConversationForBookmark(position);
+ }
+ });
mContactsAdapter = new ListItemAdapter(contacts);
mContactsListFragment.setListAdapter(mContactsAdapter);
+ mContactsListFragment.setContextMenu(R.menu.contact_context);
mContactsListFragment
.setOnListItemClickListener(new OnItemClickListener() {
@@ -192,18 +206,35 @@ public class StartConversation extends XmppActivity {
Conversation conversation = xmppConnectionService
.findOrCreateConversation(contact.getAccount(),
contact.getJid(), false);
- switchToConversation(conversation, null, false);
+ switchToConversation(conversation);
+ }
+
+ protected void openConversationForContact() {
+ int position = contact_context_id;
+ openConversationForContact(position);
+ }
+
+ protected void openConversationForBookmark() {
+ openConversationForBookmark(conference_context_id);
+ }
+
+ protected void openConversationForBookmark(int position) {
+ Bookmark bookmark = (Bookmark) conferences.get(position);
+ Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), bookmark.getJid(), true);
+ switchToConversation(conversation);
}
- protected void openDetailsForContact(int position) {
+ protected void openDetailsForContact() {
+ int position = contact_context_id;
Contact contact = (Contact) contacts.get(position);
switchToContactDetails(contact);
}
- protected void deleteContact(int position) {
+ protected void deleteContact() {
+ int position = contact_context_id;
Contact contact = (Contact) contacts.get(position);
xmppConnectionService.deleteContactOnServer(contact);
- filterContacts(mSearchEditText.getText().toString());
+ filter(mSearchEditText.getText().toString());
}
protected void showCreateContactDialog() {
@@ -339,9 +370,9 @@ public class StartConversation extends XmppActivity {
@Override
void onBackendConnected() {
if (mSearchEditText != null) {
- filterContacts(mSearchEditText.getText().toString());
+ filter(mSearchEditText.getText().toString());
} else {
- filterContacts(null);
+ filter(null);
}
this.mActivatedAccounts.clear();
for (Account account : xmppConnectionService.getAccounts()) {
@@ -353,6 +384,11 @@ public class StartConversation extends XmppActivity {
this.mKnownConferenceHosts = xmppConnectionService
.getKnownConferenceHosts();
}
+
+ protected void filter(String needle) {
+ this.filterContacts(needle);
+ this.filterConferences(needle);
+ }
protected void filterContacts(String needle) {
this.contacts.clear();
@@ -368,6 +404,21 @@ public class StartConversation extends XmppActivity {
Collections.sort(this.contacts);
mContactsAdapter.notifyDataSetChanged();
}
+
+ protected void filterConferences(String needle) {
+ this.conferences.clear();
+ for (Account account : xmppConnectionService.getAccounts()) {
+ if (account.getStatus() != Account.STATUS_DISABLED) {
+ for(Bookmark bookmark : account.getBookmarks()) {
+ if (bookmark.match(needle)) {
+ this.conferences.add(bookmark);
+ }
+ }
+ }
+ }
+ Collections.sort(this.conferences);
+ mConferenceAdapter.notifyDataSetChanged();
+ }
private void onTabChanged() {
invalidateOptionsMenu();
@@ -403,7 +454,11 @@ public class StartConversation extends XmppActivity {
public static class MyListFragment extends ListFragment {
private AdapterView.OnItemClickListener mOnItemClickListener;
- private int mContextPosition = -1;
+ private int mResContextMenu;
+
+ public void setContextMenu(int res) {
+ this.mResContextMenu = res;
+ }
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
@@ -426,10 +481,15 @@ public class StartConversation extends XmppActivity {
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
- getActivity().getMenuInflater().inflate(R.menu.contact_context,
+ StartConversation activity = (StartConversation) getActivity();
+ activity.getMenuInflater().inflate(mResContextMenu,
menu);
AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
- this.mContextPosition = acmi.position;
+ if (mResContextMenu == R.menu.conference_context) {
+ activity.conference_context_id = acmi.position;
+ } else {
+ activity.contact_context_id = acmi.position;
+ }
}
@Override
@@ -437,13 +497,16 @@ public class StartConversation extends XmppActivity {
StartConversation activity = (StartConversation) getActivity();
switch (item.getItemId()) {
case R.id.context_start_conversation:
- activity.openConversationForContact(mContextPosition);
+ activity.openConversationForContact();
break;
case R.id.context_contact_details:
- activity.openDetailsForContact(mContextPosition);
+ activity.openDetailsForContact();
break;
case R.id.context_delete_contact:
- activity.deleteContact(mContextPosition);
+ activity.deleteContact();
+ break;
+ case R.id.context_join_conference:
+ activity.openConversationForBookmark();
break;
}
return true;