434 files changed, 7009 insertions(+), 90 deletions(-)
M .gitignore
D .gitmodules
D .project
M README.md
A build.gradle
D custom_rules.xml
A gradle/wrapper/gradle-wrapper.jar
A gradle/wrapper/gradle-wrapper.properties
A gradlew
A gradlew.bat
D libs/MemorizingTrustManager
A libs/MemorizingTrustManager/.gitignore
A libs/MemorizingTrustManager/AndroidManifest.xml
A libs/MemorizingTrustManager/LICENSE.txt
A libs/MemorizingTrustManager/README.mdwn
A libs/MemorizingTrustManager/ant.properties
A libs/MemorizingTrustManager/build.gradle
R build.xml => libs/MemorizingTrustManager/build.xml
A libs/MemorizingTrustManager/example/AndroidManifest.xml
A libs/MemorizingTrustManager/example/ant.properties
A libs/MemorizingTrustManager/example/build.gradle
A libs/MemorizingTrustManager/example/build.xml
A libs/MemorizingTrustManager/example/proguard-project.txt
A libs/MemorizingTrustManager/example/project.properties
A libs/MemorizingTrustManager/example/res/layout/mtmexample.xml
A libs/MemorizingTrustManager/example/res/values/strings.xml
A libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java
A libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java
A libs/MemorizingTrustManager/libs/.android_sucks
A libs/MemorizingTrustManager/mtm-notification.png
A libs/MemorizingTrustManager/mtm-screenshot.png
A libs/MemorizingTrustManager/mtm-servername.png
A libs/MemorizingTrustManager/proguard-project.txt
A libs/MemorizingTrustManager/project.properties
A libs/MemorizingTrustManager/res/values-de/strings.xml
A libs/MemorizingTrustManager/res/values-es/strings.xml
A libs/MemorizingTrustManager/res/values-eu/strings.xml
A libs/MemorizingTrustManager/res/values-fi/strings.xml
A libs/MemorizingTrustManager/res/values-fr/strings.xml
A libs/MemorizingTrustManager/res/values-no/strings.xml
A libs/MemorizingTrustManager/res/values/strings.xml
A libs/MemorizingTrustManager/settings.gradle
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MTMDecision.java
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingActivity.java
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java
D libs/android-support-v13.jar
D libs/bcprov-jdk15on-150.jar
D libs/minidns
A libs/minidns/.gitignore
A libs/minidns/LICENCE
A libs/minidns/LICENCE_APACHE
A libs/minidns/LICENCE_LGPL2.1
A libs/minidns/LICENCE_WTFPL
A libs/minidns/README.md
A libs/minidns/build.gradle
A libs/minidns/gradle.properties.example
A libs/minidns/src/main/java/de/measite/minidns/Client.java
A libs/minidns/src/main/java/de/measite/minidns/DNSCache.java
A libs/minidns/src/main/java/de/measite/minidns/DNSMessage.java
A libs/minidns/src/main/java/de/measite/minidns/LRUCache.java
A libs/minidns/src/main/java/de/measite/minidns/Question.java
A libs/minidns/src/main/java/de/measite/minidns/Record.java
A libs/minidns/src/main/java/de/measite/minidns/record/A.java
A libs/minidns/src/main/java/de/measite/minidns/record/AAAA.java
A libs/minidns/src/main/java/de/measite/minidns/record/CNAME.java
A libs/minidns/src/main/java/de/measite/minidns/record/Data.java
A libs/minidns/src/main/java/de/measite/minidns/record/NS.java
A libs/minidns/src/main/java/de/measite/minidns/record/PTR.java
A libs/minidns/src/main/java/de/measite/minidns/record/SRV.java
A libs/minidns/src/main/java/de/measite/minidns/record/TXT.java
A libs/minidns/src/main/java/de/measite/minidns/util/NameUtil.java
D libs/openpgp-api-lib
A libs/openpgp-api-lib/.gitignore
A libs/openpgp-api-lib/.tx/config
A libs/openpgp-api-lib/AndroidManifest.xml
A libs/openpgp-api-lib/LICENSE
A libs/openpgp-api-lib/README.md
A libs/openpgp-api-lib/build.gradle
A libs/openpgp-api-lib/build.xml
A libs/openpgp-api-lib/proguard-project.txt
R project.properties => libs/openpgp-api-lib/project.properties
A libs/openpgp-api-lib/res/drawable-hdpi/ic_action_cancel_launchersize.png
A libs/openpgp-api-lib/res/drawable-hdpi/ic_action_cancel_launchersize_light.png
A libs/openpgp-api-lib/res/drawable-mdpi/ic_action_cancel_launchersize.png
A libs/openpgp-api-lib/res/drawable-mdpi/ic_action_cancel_launchersize_light.png
A libs/openpgp-api-lib/res/drawable-xhdpi/ic_action_cancel_launchersize.png
A libs/openpgp-api-lib/res/drawable-xhdpi/ic_action_cancel_launchersize_light.png
A libs/openpgp-api-lib/res/drawable-xxhdpi/ic_action_cancel_launchersize.png
A libs/openpgp-api-lib/res/drawable-xxhdpi/ic_action_cancel_launchersize_light.png
A libs/openpgp-api-lib/res/values-cs/strings.xml
A libs/openpgp-api-lib/res/values-de/strings.xml
A libs/openpgp-api-lib/res/values-es/strings.xml
A libs/openpgp-api-lib/res/values-et/strings.xml
A libs/openpgp-api-lib/res/values-fi/strings.xml
A libs/openpgp-api-lib/res/values-fr/strings.xml
A libs/openpgp-api-lib/res/values-is/strings.xml
A libs/openpgp-api-lib/res/values-it/strings.xml
A libs/openpgp-api-lib/res/values-ja/strings.xml
A libs/openpgp-api-lib/res/values-nl/strings.xml
A libs/openpgp-api-lib/res/values-pl/strings.xml
A libs/openpgp-api-lib/res/values-pt/strings.xml
A libs/openpgp-api-lib/res/values-ru/strings.xml
A libs/openpgp-api-lib/res/values-sl/strings.xml
A libs/openpgp-api-lib/res/values-tr/strings.xml
A libs/openpgp-api-lib/res/values-uk/strings.xml
A libs/openpgp-api-lib/res/values-zh/strings.xml
A libs/openpgp-api-lib/res/values/strings.xml
A libs/openpgp-api-lib/src/org/openintents/openpgp/IOpenPgpService.aidl
A libs/openpgp-api-lib/src/org/openintents/openpgp/OpenPgpError.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/OpenPgpMetadata.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/OpenPgpSignatureResult.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/util/OpenPgpApi.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/util/OpenPgpListPreference.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/util/OpenPgpServiceConnection.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/util/OpenPgpUtils.java
A libs/openpgp-api-lib/src/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java
D libs/otr4j-0.10.jar
A proguard-rules.txt
A settings.gradle
R AndroidManifest.xml => src/main/AndroidManifest.xml
R src/{eu/siacs/conversations/Config.java => main/java/eu/siacs/conversations/Config.java}
R src/{eu/siacs/conversations/crypto/OtrEngine.java => main/java/eu/siacs/conversations/crypto/OtrEngine.java}
R src/{eu/siacs/conversations/crypto/PgpEngine.java => main/java/eu/siacs/conversations/crypto/PgpEngine.java}
R src/{eu/siacs/conversations/entities/AbstractEntity.java => main/java/eu/siacs/conversations/entities/AbstractEntity.java}
R src/{eu/siacs/conversations/entities/Account.java => main/java/eu/siacs/conversations/entities/Account.java}
R src/{eu/siacs/conversations/entities/Bookmark.java => main/java/eu/siacs/conversations/entities/Bookmark.java}
R src/{eu/siacs/conversations/entities/Contact.java => main/java/eu/siacs/conversations/entities/Contact.java}
R src/{eu/siacs/conversations/entities/Conversation.java => main/java/eu/siacs/conversations/entities/Conversation.java}
R src/{eu/siacs/conversations/entities/Downloadable.java => main/java/eu/siacs/conversations/entities/Downloadable.java}
R src/{eu/siacs/conversations/entities/DownloadableFile.java => main/java/eu/siacs/conversations/entities/DownloadableFile.java}
R src/{eu/siacs/conversations/entities/ListItem.java => main/java/eu/siacs/conversations/entities/ListItem.java}
R src/{eu/siacs/conversations/entities/Message.java => main/java/eu/siacs/conversations/entities/Message.java}
R src/{eu/siacs/conversations/entities/MucOptions.java => main/java/eu/siacs/conversations/entities/MucOptions.java}
R src/{eu/siacs/conversations/entities/Presences.java => main/java/eu/siacs/conversations/entities/Presences.java}
R src/{eu/siacs/conversations/entities/Roster.java => main/java/eu/siacs/conversations/entities/Roster.java}
R src/{eu/siacs/conversations/generator/AbstractGenerator.java => main/java/eu/siacs/conversations/generator/AbstractGenerator.java}
R src/{eu/siacs/conversations/generator/IqGenerator.java => main/java/eu/siacs/conversations/generator/IqGenerator.java}
R src/{eu/siacs/conversations/generator/MessageGenerator.java => main/java/eu/siacs/conversations/generator/MessageGenerator.java}
R src/{eu/siacs/conversations/generator/PresenceGenerator.java => main/java/eu/siacs/conversations/generator/PresenceGenerator.java}
R src/{eu/siacs/conversations/http/HttpConnection.java => main/java/eu/siacs/conversations/http/HttpConnection.java}
R src/{eu/siacs/conversations/http/HttpConnectionManager.java => main/java/eu/siacs/conversations/http/HttpConnectionManager.java}
R src/{eu/siacs/conversations/parser/AbstractParser.java => main/java/eu/siacs/conversations/parser/AbstractParser.java}
R src/{eu/siacs/conversations/parser/IqParser.java => main/java/eu/siacs/conversations/parser/IqParser.java}
R src/{eu/siacs/conversations/parser/MessageParser.java => main/java/eu/siacs/conversations/parser/MessageParser.java}
R src/{eu/siacs/conversations/parser/PresenceParser.java => main/java/eu/siacs/conversations/parser/PresenceParser.java}
R src/{eu/siacs/conversations/persistance/DatabaseBackend.java => main/java/eu/siacs/conversations/persistance/DatabaseBackend.java}
R src/{eu/siacs/conversations/persistance/FileBackend.java => main/java/eu/siacs/conversations/persistance/FileBackend.java}
R src/{eu/siacs/conversations/persistance/OnPhoneContactsMerged.java => main/java/eu/siacs/conversations/persistance/OnPhoneContactsMerged.java}
R src/{eu/siacs/conversations/services/AbstractConnectionManager.java => main/java/eu/siacs/conversations/services/AbstractConnectionManager.java}
R src/{eu/siacs/conversations/services/AvatarService.java => main/java/eu/siacs/conversations/services/AvatarService.java}
R src/{eu/siacs/conversations/services/EventReceiver.java => main/java/eu/siacs/conversations/services/EventReceiver.java}
R src/{eu/siacs/conversations/services/NotificationService.java => main/java/eu/siacs/conversations/services/NotificationService.java}
R src/{eu/siacs/conversations/services/XmppConnectionService.java => main/java/eu/siacs/conversations/services/XmppConnectionService.java}
R src/{eu/siacs/conversations/ui/ChooseContactActivity.java => main/java/eu/siacs/conversations/ui/ChooseContactActivity.java}
R src/{eu/siacs/conversations/ui/ConferenceDetailsActivity.java => main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java}
R src/{eu/siacs/conversations/ui/ContactDetailsActivity.java => main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java}
R src/{eu/siacs/conversations/ui/ConversationActivity.java => main/java/eu/siacs/conversations/ui/ConversationActivity.java}
R src/{eu/siacs/conversations/ui/ConversationFragment.java => main/java/eu/siacs/conversations/ui/ConversationFragment.java}
R src/{eu/siacs/conversations/ui/EditAccountActivity.java => main/java/eu/siacs/conversations/ui/EditAccountActivity.java}
R src/{eu/siacs/conversations/ui/EditMessage.java => main/java/eu/siacs/conversations/ui/EditMessage.java}
R src/{eu/siacs/conversations/ui/ManageAccountActivity.java => main/java/eu/siacs/conversations/ui/ManageAccountActivity.java}
R src/{eu/siacs/conversations/ui/PublishProfilePictureActivity.java => main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java}
R src/{eu/siacs/conversations/ui/SettingsActivity.java => main/java/eu/siacs/conversations/ui/SettingsActivity.java}
R src/{eu/siacs/conversations/ui/SettingsFragment.java => main/java/eu/siacs/conversations/ui/SettingsFragment.java}
R src/{eu/siacs/conversations/ui/ShareWithActivity.java => main/java/eu/siacs/conversations/ui/ShareWithActivity.java}
R src/{eu/siacs/conversations/ui/StartConversationActivity.java => main/java/eu/siacs/conversations/ui/StartConversationActivity.java}
R src/{eu/siacs/conversations/ui/UiCallback.java => main/java/eu/siacs/conversations/ui/UiCallback.java}
R src/{eu/siacs/conversations/ui/XmppActivity.java => main/java/eu/siacs/conversations/ui/XmppActivity.java}
R src/{eu/siacs/conversations/ui/adapter/AccountAdapter.java => main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java}
R src/{eu/siacs/conversations/ui/adapter/ConversationAdapter.java => main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java}
R src/{eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java => main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java}
R src/{eu/siacs/conversations/ui/adapter/ListItemAdapter.java => main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java}
R src/{eu/siacs/conversations/ui/adapter/MessageAdapter.java => main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java}
R src/{eu/siacs/conversations/utils/CryptoHelper.java => main/java/eu/siacs/conversations/utils/CryptoHelper.java}
R src/{eu/siacs/conversations/utils/DNSHelper.java => main/java/eu/siacs/conversations/utils/DNSHelper.java}
R src/{eu/siacs/conversations/utils/ExceptionHandler.java => main/java/eu/siacs/conversations/utils/ExceptionHandler.java}
R src/{eu/siacs/conversations/utils/ExceptionHelper.java => main/java/eu/siacs/conversations/utils/ExceptionHelper.java}
R src/{eu/siacs/conversations/utils/ExifHelper.java => main/java/eu/siacs/conversations/utils/ExifHelper.java}
R src/{eu/siacs/conversations/utils/OnPhoneContactsLoadedListener.java => main/java/eu/siacs/conversations/utils/OnPhoneContactsLoadedListener.java}
R src/{eu/siacs/conversations/utils/PRNGFixes.java => main/java/eu/siacs/conversations/utils/PRNGFixes.java}
R src/{eu/siacs/conversations/utils/PhoneHelper.java => main/java/eu/siacs/conversations/utils/PhoneHelper.java}
R src/{eu/siacs/conversations/utils/UIHelper.java => main/java/eu/siacs/conversations/utils/UIHelper.java}
R src/{eu/siacs/conversations/utils/Validator.java => main/java/eu/siacs/conversations/utils/Validator.java}
R src/{eu/siacs/conversations/utils/XmlHelper.java => main/java/eu/siacs/conversations/utils/XmlHelper.java}
R src/{eu/siacs/conversations/utils/zlib/ZLibInputStream.java => main/java/eu/siacs/conversations/utils/zlib/ZLibInputStream.java}
R src/{eu/siacs/conversations/utils/zlib/ZLibOutputStream.java => main/java/eu/siacs/conversations/utils/zlib/ZLibOutputStream.java}
R src/{eu/siacs/conversations/xml/Element.java => main/java/eu/siacs/conversations/xml/Element.java}
R src/{eu/siacs/conversations/xml/Tag.java => main/java/eu/siacs/conversations/xml/Tag.java}
R src/{eu/siacs/conversations/xml/TagWriter.java => main/java/eu/siacs/conversations/xml/TagWriter.java}
R src/{eu/siacs/conversations/xml/XmlReader.java => main/java/eu/siacs/conversations/xml/XmlReader.java}
R src/{eu/siacs/conversations/xmpp/OnBindListener.java => main/java/eu/siacs/conversations/xmpp/OnBindListener.java}
R src/{eu/siacs/conversations/xmpp/OnContactStatusChanged.java => main/java/eu/siacs/conversations/xmpp/OnContactStatusChanged.java}
R src/{eu/siacs/conversations/xmpp/OnIqPacketReceived.java => main/java/eu/siacs/conversations/xmpp/OnIqPacketReceived.java}
R src/{eu/siacs/conversations/xmpp/OnMessageAcknowledged.java => main/java/eu/siacs/conversations/xmpp/OnMessageAcknowledged.java}
R src/{eu/siacs/conversations/xmpp/OnMessagePacketReceived.java => main/java/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java}
R src/{eu/siacs/conversations/xmpp/OnPresencePacketReceived.java => main/java/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java}
R src/{eu/siacs/conversations/xmpp/OnStatusChanged.java => main/java/eu/siacs/conversations/xmpp/OnStatusChanged.java}
R src/{eu/siacs/conversations/xmpp/PacketReceived.java => main/java/eu/siacs/conversations/xmpp/PacketReceived.java}
R src/{eu/siacs/conversations/xmpp/XmppConnection.java => main/java/eu/siacs/conversations/xmpp/XmppConnection.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleCandidate.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleConnection.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java}
R src/{eu/siacs/conversations/xmpp/jingle/JingleTransport.java => main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java}
R src/{eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java => main/java/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java}
R src/{eu/siacs/conversations/xmpp/jingle/OnJinglePacketReceived.java => main/java/eu/siacs/conversations/xmpp/jingle/OnJinglePacketReceived.java}
R src/{eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java => main/java/eu/siacs/conversations/xmpp/jingle/OnPrimaryCandidateFound.java}
R src/{eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java => main/java/eu/siacs/conversations/xmpp/jingle/OnTransportConnected.java}
R src/{eu/siacs/conversations/xmpp/jingle/stanzas/Content.java => main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java}
R src/{eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java => main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java}
R src/{eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java => main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java}
R src/{eu/siacs/conversations/xmpp/pep/Avatar.java => main/java/eu/siacs/conversations/xmpp/pep/Avatar.java}
R src/{eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java => main/java/eu/siacs/conversations/xmpp/stanzas/AbstractStanza.java}
R src/{eu/siacs/conversations/xmpp/stanzas/IqPacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/IqPacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/MessagePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/PresencePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/PresencePacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/csi/ActivePacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/csi/InactivePacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/streammgmt/AckPacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/streammgmt/EnablePacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/streammgmt/RequestPacket.java}
R src/{eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java => main/java/eu/siacs/conversations/xmpp/stanzas/streammgmt/ResumePacket.java}
R res/drawable-hdpi/ic_action_add_group.png => src/main/res/drawable-hdpi/ic_action_add_group.png
R res/drawable-hdpi/ic_action_add_person.png => src/main/res/drawable-hdpi/ic_action_add_person.png
R res/drawable-hdpi/ic_action_chat.png => src/main/res/drawable-hdpi/ic_action_chat.png
R res/drawable-hdpi/ic_action_copy.png => src/main/res/drawable-hdpi/ic_action_copy.png
R res/drawable-hdpi/ic_action_discard.png => src/main/res/drawable-hdpi/ic_action_discard.png
R res/drawable-hdpi/ic_action_edit.png => src/main/res/drawable-hdpi/ic_action_edit.png
R res/drawable-hdpi/ic_action_edit_dark.png => src/main/res/drawable-hdpi/ic_action_edit_dark.png
R res/drawable-hdpi/ic_action_group.png => src/main/res/drawable-hdpi/ic_action_group.png
R res/drawable-hdpi/ic_action_new.png => src/main/res/drawable-hdpi/ic_action_new.png
R res/drawable-hdpi/ic_action_new_attachment.png => src/main/res/drawable-hdpi/ic_action_new_attachment.png
R res/drawable-hdpi/ic_action_not_secure.png => src/main/res/drawable-hdpi/ic_action_not_secure.png
R res/drawable-hdpi/ic_action_refresh.png => src/main/res/drawable-hdpi/ic_action_refresh.png
R res/drawable-hdpi/ic_action_remove.png => src/main/res/drawable-hdpi/ic_action_remove.png
R res/drawable-hdpi/ic_action_search.png => src/main/res/drawable-hdpi/ic_action_search.png
R res/drawable-hdpi/ic_action_secure.png => src/main/res/drawable-hdpi/ic_action_secure.png
R res/drawable-hdpi/ic_action_send_now_away.png => src/main/res/drawable-hdpi/ic_action_send_now_away.png
R res/drawable-hdpi/ic_action_send_now_dnd.png => src/main/res/drawable-hdpi/ic_action_send_now_dnd.png
R res/drawable-hdpi/ic_action_send_now_offline.png => src/main/res/drawable-hdpi/ic_action_send_now_offline.png
R res/drawable-hdpi/ic_action_send_now_online.png => src/main/res/drawable-hdpi/ic_action_send_now_online.png
R res/drawable-hdpi/ic_activity.png => src/main/res/drawable-hdpi/ic_activity.png
R res/drawable-hdpi/ic_indicator.png => src/main/res/drawable-hdpi/ic_indicator.png
R res/drawable-hdpi/ic_launcher.png => src/main/res/drawable-hdpi/ic_launcher.png
R res/drawable-hdpi/ic_notification.png => src/main/res/drawable-hdpi/ic_notification.png
R res/drawable-hdpi/ic_profile.png => src/main/res/drawable-hdpi/ic_profile.png
R res/drawable-hdpi/ic_received_indicator.png => src/main/res/drawable-hdpi/ic_received_indicator.png
R res/drawable-hdpi/ic_secure_indicator.png => src/main/res/drawable-hdpi/ic_secure_indicator.png
R res/drawable-hdpi/tab_selected_conversations.9.png => src/main/res/drawable-hdpi/tab_selected_conversations.9.png
R res/drawable-hdpi/tab_selected_focused_conversations.9.png => src/main/res/drawable-hdpi/tab_selected_focused_conversations.9.png
R res/drawable-hdpi/tab_selected_pressed_conversations.9.png => src/main/res/drawable-hdpi/tab_selected_pressed_conversations.9.png
R res/drawable-hdpi/tab_unselected_conversations.9.png => src/main/res/drawable-hdpi/tab_unselected_conversations.9.png
R res/drawable-hdpi/tab_unselected_focused_conversations.9.png => src/main/res/drawable-hdpi/tab_unselected_focused_conversations.9.png
R res/drawable-hdpi/tab_unselected_pressed_conversations.9.png => src/main/res/drawable-hdpi/tab_unselected_pressed_conversations.9.png
R res/drawable-mdpi/ic_action_add_group.png => src/main/res/drawable-mdpi/ic_action_add_group.png
R res/drawable-mdpi/ic_action_add_person.png => src/main/res/drawable-mdpi/ic_action_add_person.png
R res/drawable-mdpi/ic_action_chat.png => src/main/res/drawable-mdpi/ic_action_chat.png
R res/drawable-mdpi/ic_action_copy.png => src/main/res/drawable-mdpi/ic_action_copy.png
R res/drawable-mdpi/ic_action_discard.png => src/main/res/drawable-mdpi/ic_action_discard.png
R res/drawable-mdpi/ic_action_edit.png => src/main/res/drawable-mdpi/ic_action_edit.png
R res/drawable-mdpi/ic_action_edit_dark.png => src/main/res/drawable-mdpi/ic_action_edit_dark.png
R res/drawable-mdpi/ic_action_group.png => src/main/res/drawable-mdpi/ic_action_group.png
R res/drawable-mdpi/ic_action_new.png => src/main/res/drawable-mdpi/ic_action_new.png
R res/drawable-mdpi/ic_action_new_attachment.png => src/main/res/drawable-mdpi/ic_action_new_attachment.png
R res/drawable-mdpi/ic_action_not_secure.png => src/main/res/drawable-mdpi/ic_action_not_secure.png
R res/drawable-mdpi/ic_action_refresh.png => src/main/res/drawable-mdpi/ic_action_refresh.png
R res/drawable-mdpi/ic_action_remove.png => src/main/res/drawable-mdpi/ic_action_remove.png
R res/drawable-mdpi/ic_action_search.png => src/main/res/drawable-mdpi/ic_action_search.png
R res/drawable-mdpi/ic_action_secure.png => src/main/res/drawable-mdpi/ic_action_secure.png
R res/drawable-mdpi/ic_action_send_now_away.png => src/main/res/drawable-mdpi/ic_action_send_now_away.png
R res/drawable-mdpi/ic_action_send_now_dnd.png => src/main/res/drawable-mdpi/ic_action_send_now_dnd.png
R res/drawable-mdpi/ic_action_send_now_offline.png => src/main/res/drawable-mdpi/ic_action_send_now_offline.png
R res/drawable-mdpi/ic_action_send_now_online.png => src/main/res/drawable-mdpi/ic_action_send_now_online.png
R res/drawable-mdpi/ic_activity.png => src/main/res/drawable-mdpi/ic_activity.png
R res/drawable-mdpi/ic_indicator.png => src/main/res/drawable-mdpi/ic_indicator.png
R res/drawable-mdpi/ic_launcher.png => src/main/res/drawable-mdpi/ic_launcher.png
R res/drawable-mdpi/ic_notification.png => src/main/res/drawable-mdpi/ic_notification.png
R res/drawable-mdpi/ic_profile.png => src/main/res/drawable-mdpi/ic_profile.png
R res/drawable-mdpi/ic_received_indicator.png => src/main/res/drawable-mdpi/ic_received_indicator.png
R res/drawable-mdpi/ic_secure_indicator.png => src/main/res/drawable-mdpi/ic_secure_indicator.png
R res/drawable-mdpi/tab_selected_conversations.9.png => src/main/res/drawable-mdpi/tab_selected_conversations.9.png
R res/drawable-mdpi/tab_selected_focused_conversations.9.png => src/main/res/drawable-mdpi/tab_selected_focused_conversations.9.png
R res/drawable-mdpi/tab_selected_pressed_conversations.9.png => src/main/res/drawable-mdpi/tab_selected_pressed_conversations.9.png
R res/drawable-mdpi/tab_unselected_conversations.9.png => src/main/res/drawable-mdpi/tab_unselected_conversations.9.png
R res/drawable-mdpi/tab_unselected_focused_conversations.9.png => src/main/res/drawable-mdpi/tab_unselected_focused_conversations.9.png
R res/drawable-mdpi/tab_unselected_pressed_conversations.9.png => src/main/res/drawable-mdpi/tab_unselected_pressed_conversations.9.png
R res/drawable-xhdpi/ic_action_add_group.png => src/main/res/drawable-xhdpi/ic_action_add_group.png
R res/drawable-xhdpi/ic_action_add_person.png => src/main/res/drawable-xhdpi/ic_action_add_person.png
R res/drawable-xhdpi/ic_action_chat.png => src/main/res/drawable-xhdpi/ic_action_chat.png
R res/drawable-xhdpi/ic_action_copy.png => src/main/res/drawable-xhdpi/ic_action_copy.png
R res/drawable-xhdpi/ic_action_discard.png => src/main/res/drawable-xhdpi/ic_action_discard.png
R res/drawable-xhdpi/ic_action_edit.png => src/main/res/drawable-xhdpi/ic_action_edit.png
R res/drawable-xhdpi/ic_action_edit_dark.png => src/main/res/drawable-xhdpi/ic_action_edit_dark.png
R res/drawable-xhdpi/ic_action_group.png => src/main/res/drawable-xhdpi/ic_action_group.png
R res/drawable-xhdpi/ic_action_new.png => src/main/res/drawable-xhdpi/ic_action_new.png
R res/drawable-xhdpi/ic_action_new_attachment.png => src/main/res/drawable-xhdpi/ic_action_new_attachment.png
R res/drawable-xhdpi/ic_action_not_secure.png => src/main/res/drawable-xhdpi/ic_action_not_secure.png
R res/drawable-xhdpi/ic_action_refresh.png => src/main/res/drawable-xhdpi/ic_action_refresh.png
R res/drawable-xhdpi/ic_action_remove.png => src/main/res/drawable-xhdpi/ic_action_remove.png
R res/drawable-xhdpi/ic_action_search.png => src/main/res/drawable-xhdpi/ic_action_search.png
R res/drawable-xhdpi/ic_action_secure.png => src/main/res/drawable-xhdpi/ic_action_secure.png
R res/drawable-xhdpi/ic_action_send_now_away.png => src/main/res/drawable-xhdpi/ic_action_send_now_away.png
R res/drawable-xhdpi/ic_action_send_now_dnd.png => src/main/res/drawable-xhdpi/ic_action_send_now_dnd.png
R res/drawable-xhdpi/ic_action_send_now_offline.png => src/main/res/drawable-xhdpi/ic_action_send_now_offline.png
R res/drawable-xhdpi/ic_action_send_now_online.png => src/main/res/drawable-xhdpi/ic_action_send_now_online.png
R res/drawable-xhdpi/ic_activity.png => src/main/res/drawable-xhdpi/ic_activity.png
R res/drawable-xhdpi/ic_indicator.png => src/main/res/drawable-xhdpi/ic_indicator.png
R res/drawable-xhdpi/ic_launcher.png => src/main/res/drawable-xhdpi/ic_launcher.png
R res/drawable-xhdpi/ic_notification.png => src/main/res/drawable-xhdpi/ic_notification.png
R res/drawable-xhdpi/ic_profile.png => src/main/res/drawable-xhdpi/ic_profile.png
R res/drawable-xhdpi/ic_received_indicator.png => src/main/res/drawable-xhdpi/ic_received_indicator.png
R res/drawable-xhdpi/ic_secure_indicator.png => src/main/res/drawable-xhdpi/ic_secure_indicator.png
R res/drawable-xhdpi/tab_selected_conversations.9.png => src/main/res/drawable-xhdpi/tab_selected_conversations.9.png
R res/drawable-xhdpi/tab_selected_focused_conversations.9.png => src/main/res/drawable-xhdpi/tab_selected_focused_conversations.9.png
R res/drawable-xhdpi/tab_selected_pressed_conversations.9.png => src/main/res/drawable-xhdpi/tab_selected_pressed_conversations.9.png
R res/drawable-xhdpi/tab_unselected_conversations.9.png => src/main/res/drawable-xhdpi/tab_unselected_conversations.9.png
R res/drawable-xhdpi/tab_unselected_focused_conversations.9.png => src/main/res/drawable-xhdpi/tab_unselected_focused_conversations.9.png
R res/drawable-xhdpi/tab_unselected_pressed_conversations.9.png => src/main/res/drawable-xhdpi/tab_unselected_pressed_conversations.9.png
R res/drawable-xxhdpi/ic_action_add_group.png => src/main/res/drawable-xxhdpi/ic_action_add_group.png
R res/drawable-xxhdpi/ic_action_add_person.png => src/main/res/drawable-xxhdpi/ic_action_add_person.png
R res/drawable-xxhdpi/ic_action_chat.png => src/main/res/drawable-xxhdpi/ic_action_chat.png
R res/drawable-xxhdpi/ic_action_copy.png => src/main/res/drawable-xxhdpi/ic_action_copy.png
R res/drawable-xxhdpi/ic_action_discard.png => src/main/res/drawable-xxhdpi/ic_action_discard.png
R res/drawable-xxhdpi/ic_action_edit.png => src/main/res/drawable-xxhdpi/ic_action_edit.png
R res/drawable-xxhdpi/ic_action_edit_dark.png => src/main/res/drawable-xxhdpi/ic_action_edit_dark.png
R res/drawable-xxhdpi/ic_action_group.png => src/main/res/drawable-xxhdpi/ic_action_group.png
R res/drawable-xxhdpi/ic_action_new.png => src/main/res/drawable-xxhdpi/ic_action_new.png
R res/drawable-xxhdpi/ic_action_new_attachment.png => src/main/res/drawable-xxhdpi/ic_action_new_attachment.png
R res/drawable-xxhdpi/ic_action_not_secure.png => src/main/res/drawable-xxhdpi/ic_action_not_secure.png
R res/drawable-xxhdpi/ic_action_refresh.png => src/main/res/drawable-xxhdpi/ic_action_refresh.png
R res/drawable-xxhdpi/ic_action_remove.png => src/main/res/drawable-xxhdpi/ic_action_remove.png
R res/drawable-xxhdpi/ic_action_search.png => src/main/res/drawable-xxhdpi/ic_action_search.png
R res/drawable-xxhdpi/ic_action_secure.png => src/main/res/drawable-xxhdpi/ic_action_secure.png
R res/drawable-xxhdpi/ic_action_send_now_away.png => src/main/res/drawable-xxhdpi/ic_action_send_now_away.png
R res/drawable-xxhdpi/ic_action_send_now_dnd.png => src/main/res/drawable-xxhdpi/ic_action_send_now_dnd.png
R res/drawable-xxhdpi/ic_action_send_now_offline.png => src/main/res/drawable-xxhdpi/ic_action_send_now_offline.png
R res/drawable-xxhdpi/ic_action_send_now_online.png => src/main/res/drawable-xxhdpi/ic_action_send_now_online.png
R res/drawable-xxhdpi/ic_activity.png => src/main/res/drawable-xxhdpi/ic_activity.png
R res/drawable-xxhdpi/ic_indicator.png => src/main/res/drawable-xxhdpi/ic_indicator.png
R res/drawable-xxhdpi/ic_launcher.png => src/main/res/drawable-xxhdpi/ic_launcher.png
R res/drawable-xxhdpi/ic_notification.png => src/main/res/drawable-xxhdpi/ic_notification.png
R res/drawable-xxhdpi/ic_profile.png => src/main/res/drawable-xxhdpi/ic_profile.png
R res/drawable-xxhdpi/ic_received_indicator.png => src/main/res/drawable-xxhdpi/ic_received_indicator.png
R res/drawable-xxhdpi/ic_secure_indicator.png => src/main/res/drawable-xxhdpi/ic_secure_indicator.png
R res/drawable-xxhdpi/tab_selected_conversations.9.png => src/main/res/drawable-xxhdpi/tab_selected_conversations.9.png
R res/drawable-xxhdpi/tab_selected_focused_conversations.9.png => src/main/res/drawable-xxhdpi/tab_selected_focused_conversations.9.png
R res/drawable-xxhdpi/tab_selected_pressed_conversations.9.png => src/main/res/drawable-xxhdpi/tab_selected_pressed_conversations.9.png
R res/drawable-xxhdpi/tab_unselected_conversations.9.png => src/main/res/drawable-xxhdpi/tab_unselected_conversations.9.png
R res/drawable-xxhdpi/tab_unselected_focused_conversations.9.png => src/main/res/drawable-xxhdpi/tab_unselected_focused_conversations.9.png
R res/drawable-xxhdpi/tab_unselected_pressed_conversations.9.png => src/main/res/drawable-xxhdpi/tab_unselected_pressed_conversations.9.png
R res/drawable/actionbar_tab_indicator.xml => src/main/res/drawable/actionbar_tab_indicator.xml
R res/drawable/es_slidingpane_shadow.xml => src/main/res/drawable/es_slidingpane_shadow.xml
R res/drawable/grey.xml => src/main/res/drawable/grey.xml
R res/drawable/greybackground.xml => src/main/res/drawable/greybackground.xml
R res/drawable/infocard_border.xml => src/main/res/drawable/infocard_border.xml
R res/drawable/message_border.xml => src/main/res/drawable/message_border.xml
R res/drawable/snackbar.xml => src/main/res/drawable/snackbar.xml
R res/layout-w360dp/fragment_conversations_overview.xml => src/main/res/layout-w360dp/fragment_conversations_overview.xml
R res/layout-w384dp/fragment_conversations_overview.xml => src/main/res/layout-w384dp/fragment_conversations_overview.xml
R res/layout-w600dp/fragment_conversations_overview.xml => src/main/res/layout-w600dp/fragment_conversations_overview.xml
R res/layout-w960dp/fragment_conversations_overview.xml => src/main/res/layout-w960dp/fragment_conversations_overview.xml
R res/layout/account_row.xml => src/main/res/layout/account_row.xml
R res/layout/actionview_search.xml => src/main/res/layout/actionview_search.xml
R res/layout/activity_choose_contact.xml => src/main/res/layout/activity_choose_contact.xml
R res/layout/activity_contact_details.xml => src/main/res/layout/activity_contact_details.xml
R res/layout/activity_edit_account.xml => src/main/res/layout/activity_edit_account.xml
R res/layout/activity_muc_details.xml => src/main/res/layout/activity_muc_details.xml
R res/layout/activity_publish_profile_picture.xml => src/main/res/layout/activity_publish_profile_picture.xml
R res/layout/activity_start_conversation.xml => src/main/res/layout/activity_start_conversation.xml
R res/layout/contact.xml => src/main/res/layout/contact.xml
R res/layout/contact_key.xml => src/main/res/layout/contact_key.xml
R res/layout/conversation_list_row.xml => src/main/res/layout/conversation_list_row.xml
R res/layout/create_contact_dialog.xml => src/main/res/layout/create_contact_dialog.xml
R res/layout/dialog_clear_history.xml => src/main/res/layout/dialog_clear_history.xml
R res/layout/dialog_verify_otr.xml => src/main/res/layout/dialog_verify_otr.xml
R res/layout/fragment_conversation.xml => src/main/res/layout/fragment_conversation.xml
R res/layout/fragment_conversations_overview.xml => src/main/res/layout/fragment_conversations_overview.xml
R res/layout/join_conference_dialog.xml => src/main/res/layout/join_conference_dialog.xml
R res/layout/manage_accounts.xml => src/main/res/layout/manage_accounts.xml
R res/layout/message_null.xml => src/main/res/layout/message_null.xml
R res/layout/message_received.xml => src/main/res/layout/message_received.xml
R res/layout/message_sent.xml => src/main/res/layout/message_sent.xml
R res/layout/message_status.xml => src/main/res/layout/message_status.xml
R res/layout/quickedit.xml => src/main/res/layout/quickedit.xml
R res/layout/share_with.xml => src/main/res/layout/share_with.xml
R res/menu/attachment_choices.xml => src/main/res/menu/attachment_choices.xml
R res/menu/choose_contact.xml => src/main/res/menu/choose_contact.xml
R res/menu/conference_context.xml => src/main/res/menu/conference_context.xml
R res/menu/contact_context.xml => src/main/res/menu/contact_context.xml
R res/menu/contact_details.xml => src/main/res/menu/contact_details.xml
R res/menu/conversations.xml => src/main/res/menu/conversations.xml
R res/menu/encryption_choices.xml => src/main/res/menu/encryption_choices.xml
R res/menu/manageaccounts.xml => src/main/res/menu/manageaccounts.xml
R res/menu/manageaccounts_context.xml => src/main/res/menu/manageaccounts_context.xml
R res/menu/message_context.xml => src/main/res/menu/message_context.xml
R res/menu/muc_details.xml => src/main/res/menu/muc_details.xml
R res/menu/share_with.xml => src/main/res/menu/share_with.xml
R res/menu/start_conversation.xml => src/main/res/menu/start_conversation.xml
R res/values-ca/arrays.xml => src/main/res/values-ca/arrays.xml
R res/values-ca/strings.xml => src/main/res/values-ca/strings.xml
R res/values-cs/arrays.xml => src/main/res/values-cs/arrays.xml
R res/values-cs/strings.xml => src/main/res/values-cs/strings.xml
R res/values-de/arrays.xml => src/main/res/values-de/arrays.xml
R res/values-de/strings.xml => src/main/res/values-de/strings.xml
R res/values-es/arrays.xml => src/main/res/values-es/arrays.xml
R res/values-es/strings.xml => src/main/res/values-es/strings.xml
R res/values-eu/arrays.xml => src/main/res/values-eu/arrays.xml
R res/values-eu/strings.xml => src/main/res/values-eu/strings.xml
R res/values-fr/arrays.xml => src/main/res/values-fr/arrays.xml
R res/values-fr/strings.xml => src/main/res/values-fr/strings.xml
R res/values-gl/arrays.xml => src/main/res/values-gl/arrays.xml
R res/values-gl/strings.xml => src/main/res/values-gl/strings.xml
R res/values-it/arrays.xml => src/main/res/values-it/arrays.xml
R res/values-it/strings.xml => src/main/res/values-it/strings.xml
R res/values-iw/arrays.xml => src/main/res/values-iw/arrays.xml
R res/values-iw/strings.xml => src/main/res/values-iw/strings.xml
R res/values-nl/arrays.xml => src/main/res/values-nl/arrays.xml
R res/values-nl/strings.xml => src/main/res/values-nl/strings.xml
R res/values-ru/arrays.xml => src/main/res/values-ru/arrays.xml
R res/values-ru/strings.xml => src/main/res/values-ru/strings.xml
R res/values-sv/arrays.xml => src/main/res/values-sv/arrays.xml
R res/values-sv/strings.xml => src/main/res/values-sv/strings.xml
R res/values-zh-rCN/arrays.xml => src/main/res/values-zh-rCN/arrays.xml
R res/values-zh-rCN/strings.xml => src/main/res/values-zh-rCN/strings.xml
R res/values-zh-rTW/arrays.xml => src/main/res/values-zh-rTW/arrays.xml
R res/values-zh-rTW/strings.xml => src/main/res/values-zh-rTW/strings.xml
R res/values/arrays.xml => src/main/res/values/arrays.xml
R res/values/attrs.xml => src/main/res/values/attrs.xml
R res/values/colors.xml => src/main/res/values/colors.xml
R res/values/strings.xml => src/main/res/values/strings.xml
R res/values/styles.xml => src/main/res/values/styles.xml
R res/values/themes.xml => src/main/res/values/themes.xml
R res/xml/preferences.xml => src/main/res/xml/preferences.xml
M .gitignore => .gitignore +34 -2
@@ 1,6 1,38 @@
-bin/**
.classpath
*.swp
.settings
+
+# https://github.com/github/gitignore/blob/master/Gradle.gitignore
+.gradle/
+build/
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# https://github.com/github/gitignore/blob/master/Android.gitignore
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Local configuration file (sdk path, etc)
local.properties
-gen
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+*.iml
+.idea
+
+import-summary.txt
D .gitmodules => .gitmodules +0 -10
@@ 1,10 0,0 @@
-[submodule "libs/minidns"]
- path = libs/minidns
- url = https://github.com/rtreffer/minidns.git
-
-[submodule "libs/openpgp-api-lib"]
- path = libs/openpgp-api-lib
- url = https://github.com/open-keychain/openpgp-api-lib.git
-[submodule "libs/MemorizingTrustManager"]
- path = libs/MemorizingTrustManager
- url = https://github.com/iNPUTmice/MemorizingTrustManager.git
D .project => .project +0 -33
@@ 1,33 0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>Conversations</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>com.android.ide.eclipse.adt.ApkBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
M README.md => README.md +20 -3
@@ 271,9 271,26 @@ Make sure to have ANDROID_HOME point to your Android SDK
git clone https://github.com/siacs/Conversations.git
cd Conversations
- git submodule update --init --recursive
- ant clean
- ant debug
+ ./gradlew build
+
+### How do I update/add external libraries?
+
+If the library you want to update is in Maven Central or JCenter (or has its own
+Maven repo), add it or update its version in `build.gradle`. If the library is
+in the `libs/` directory, you can update it using a subtree merge by doing the
+following (using `minidns` as an example):
+
+ git remote add minidns https://github.com/rtreffer/minidns.git
+ git fetch minidns
+ git merge -s subtree minidns master
+
+To add a new dependency to the `libs/` directory (replacing "name", "branch" and
+"url" as necessary):
+
+ git remote add name url
+ git merge -s ours --no-commit name/branch
+ git read-tree --prefix=libs/name -u name/branch
+ git commit -m "Subtree merged in name"
#### How do I debug Conversations
A build.gradle => build.gradle +118 -0
@@ 0,0 1,118 @@
+// Top-level build file where you can add configuration options common to all
+// sub-projects/modules.
+buildscript {
+ repositories {
+ jcenter()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.12.2'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ mavenCentral()
+ }
+}
+
+apply plugin: 'com.android.application'
+
+repositories {
+ jcenter()
+ mavenCentral()
+ maven {
+ url "http://jitsi.github.com/otr4j/repository/"
+ }
+}
+
+dependencies {
+ compile project(':libs/minidns')
+ compile project(':libs/openpgp-api-lib')
+ compile project(':libs/MemorizingTrustManager')
+ compile 'com.android.support:support-v13:19.1.0'
+ compile 'org.bouncycastle:bcprov-jdk15on:1.50'
+ compile 'net.java:otr4j:0.21'
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "19.1"
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 19
+ versionCode 32
+ versionName "0.8-alpha"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ //
+ // To sign release builds, create the file `gradle.properties` in
+ // $HOME/.gradle or in your project directory with this content:
+ //
+ // mStoreFile=/path/to/key.store
+ // mStorePassword=xxx
+ // mKeyAlias=alias
+ // mKeyPassword=xxx
+ //
+ if (project.hasProperty('mStoreFile') &&
+ project.hasProperty('mStorePassword') &&
+ project.hasProperty('mKeyAlias') &&
+ project.hasProperty('mKeyPassword')) {
+ signingConfigs {
+ release {
+ storeFile file(mStoreFile)
+ storePassword mStorePassword
+ keyAlias mKeyAlias
+ keyPassword mKeyPassword
+ }
+ }
+ buildTypes.release.signingConfig = signingConfigs.release
+ } else {
+ buildTypes.release.signingConfig = null
+ }
+
+ buildTypes {
+ release {
+ runProguard true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+ }
+ applicationVariants.all { variant ->
+ def fileName = variant.packageApplication.outputFile.name.replace(".apk",
+ "-" + defaultConfig.versionName + ".apk")
+ variant.packageApplication.outputFile = new
+ File(variant.packageApplication.outputFile.parent, fileName)
+ if (variant.zipAlign) {
+ if (variant.name.equals('release')) {
+ variant.outputFile = new File(variant.outputFile.parent,
+ rootProject.name + "-" + defaultConfig.versionName + ".apk")
+ }
+ }
+ }
+ }
+
+ lintOptions {
+ disable 'MissingTranslation', 'InvalidPackage'
+ }
+
+ subprojects {
+
+ afterEvaluate {
+ if (getPlugins().hasPlugin('android') ||
+ getPlugins().hasPlugin('android-library')) {
+
+ configure(android.lintOptions) {
+ disable 'AndroidGradlePluginVersion', 'MissingTranslation'
+ }
+ }
+
+ }
+ }
+}
D custom_rules.xml => custom_rules.xml +0 -28
@@ 1,28 0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project>
-
- <target name="rename-release-with-version-number" >
-
- <xmlproperty
- collapseAttributes="true"
- file="AndroidManifest.xml"
- prefix="themanifest" />
-
- <property
- name="out.packaged.file"
- location="${out.absolute.dir}/${ant.project.name}-${themanifest.manifest.android:versionName}-unsigned.apk" />
-
- <property
- name="out.final.file"
- location="${out.absolute.dir}/${ant.project.name}-${themanifest.manifest.android:versionName}.apk" />
- </target>
-
- <target
- name="-set-release-mode"
- depends="rename-release-with-version-number,android_rules.-set-release-mode" >
-
- <echo message="target: ${build.target}" >
- </echo>
- </target>
-
-</project>>
\ No newline at end of file
A gradle/wrapper/gradle-wrapper.jar => gradle/wrapper/gradle-wrapper.jar +0 -0
A gradle/wrapper/gradle-wrapper.properties => gradle/wrapper/gradle-wrapper.properties +6 -0
@@ 0,0 1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
A gradlew => gradlew +164 -0
@@ 0,0 1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
A gradlew.bat => gradlew.bat +90 -0
@@ 0,0 1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
D libs/MemorizingTrustManager => libs/MemorizingTrustManager +0 -1
@@ 1,1 0,0 @@
-Subproject commit fad835037adc1bd313bb56b694426fca4eb67346
A libs/MemorizingTrustManager/.gitignore => libs/MemorizingTrustManager/.gitignore +11 -0
@@ 0,0 1,11 @@
+bin
+build
+gen
+local.properties
+example/bin
+example/gen
+tags
+.project
+.classpath
+.gradle
+.*.swp
A libs/MemorizingTrustManager/AndroidManifest.xml => libs/MemorizingTrustManager/AndroidManifest.xml +11 -0
@@ 0,0 1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.duenndns.ssl"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:label="MemorizingTrustManager">
+ <activity android:name="de.duenndns.ssl.MemorizingActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+ </application>
+</manifest>
A libs/MemorizingTrustManager/LICENSE.txt => libs/MemorizingTrustManager/LICENSE.txt +21 -0
@@ 0,0 1,21 @@
+The MIT license.
+
+Copyright (c) 2010 Georg Lukas <georg@op-co.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
A libs/MemorizingTrustManager/README.mdwn => libs/MemorizingTrustManager/README.mdwn +125 -0
@@ 0,0 1,125 @@
+# MemorizingTrustManager - Private Cloud Support for Your App
+
+MemorizingTrustManager (MTM) is a project to enable smarter and more secure use
+of SSL on Android. If it encounters an unknown SSL certificate, it asks the
+user whether to accept the certificate once, permanently or to abort the
+connection. This is a step in preventing man-in-the-middle attacks by blindly
+accepting any invalid, self-signed and/or expired certificates.
+
+MTM is aimed at providing seamless integration into your Android application,
+and the source code is available under the MIT license.
+
+## Screenshots
+
+
+
+
+
+## Status
+
+MemorizingTrustManager is in production use in the
+[yaxim XMPP client](https://yaxim.org/). It is usable and easy to integrate,
+though it does not yet support hostname validation (the Java API makes it
+**hard** to integrate).
+
+## Integration
+
+MTM is easy to integrate into your own application. Follow these steps or have
+a look into the demo application in the `example` directory.
+
+### 1. Add MTM to your project
+
+Download the MTM source from GitHub, or add it as a
+[git submodule](http://git-scm.com/docs/git-submodule):
+
+ # plain download:
+ git clone https://github.com/ge0rg/MemorizingTrustManager
+ # submodule:
+ git submodule add https://github.com/ge0rg/MemorizingTrustManager
+
+Then add a library project dependency to `default.properties`:
+
+ android.library.reference.1=MemorizingTrustManager
+
+### 2. Add the MTM (popup) Activity to your manifest
+
+Edit your `AndroidManifest.xml` and add the MTM activity element right before the
+end of your closing `</application>` tag.
+
+ ...
+ <activity android:name="de.duenndns.ssl.MemorizingActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar"
+ />
+ </application>
+ </manifest>
+
+### 3. Hook MTM as the default TrustManager for your connection type
+
+Hooking MemorizingTrustmanager in HTTPS connections:
+
+ // register MemorizingTrustManager for HTTPS
+ SSLContext sc = SSLContext.getInstance("TLS");
+ MemorizingTrustManager mtm = new MemorizingTrustManager(this);
+ sc.init(null, new X509TrustManager[] { mtm }, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(
+ mtm.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()));
+
+
+Or, for aSmack you can use `setCustomSSLContext()`:
+
+ org.jivesoftware.smack.ConnectionConfiguration connectionConfiguration = …
+ SSLContext sc = SSLContext.getInstance("TLS");
+ MemorizingTrustManager mtm = new MemorizingTrustManager(this);
+ sc.init(null, new X509TrustManager[] { mtm }, new java.security.SecureRandom());
+ connectionConfiguration.setCustomSSLContext(sc);
+ connectionConfiguration.setHostnameVerifier(
+ mtm.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier()));
+
+By default, MTM falls back to the system `TrustManager` before asking the user.
+If you do not trust the establishment, you can enforce a dialog on *every new
+connection* by supplying a `defaultTrustManager = null` parameter to the
+constructor:
+
+ MemorizingTrustManager mtm = new MemorizingTrustManager(this, null);
+
+If you want to use a different underlying `TrustManager`, like
+[AndroidPinning](https://github.com/moxie0/AndroidPinning), just supply that to
+MTM's constructor:
+
+ X509TrustManager pinning = new PinningTrustManager(SystemKeyStore.getInstance(),
+ new String[] {"f30012bbc18c231ac1a44b788e410ce754182513"}, 0);
+ MemorizingTrustManager mtm = new MemorizingTrustManager(this, pinning);
+
+### 4. Profit!
+
+### Logging
+
+MTM uses java.util.logging (JUL) for logging purposes. If you have not
+configured a Handler for JUL, then Android will by default log all
+messages of Level.INFO or higher. In order to get also the debug log
+messages (those with Level.FINE or lower) you need to configure a
+Handler accordingly. The MTM example project contains
+de.duenndns.mtmexample.JULHandler, which allows to enable and disable
+debug logging at runtime.
+
+## Alternatives
+
+MemorizingTrustManager is not the only one out there.
+
+[**NetCipher**](https://guardianproject.info/code/netcipher/) is an Android
+library made by the [Guardian Project](https://guardianproject.info/) to
+improve network security for mobile apps. It comes with a StrongTrustManager
+to do more thorough certificate checks, an independent Root CA store, and code
+to easily route your traffic through
+[the Tor network](https://www.torproject.org/) using [Orbot](https://guardianproject.info/apps/orbot/).
+
+[**AndroidPinning**](https://github.com/moxie0/AndroidPinning) is another Android
+library, written by [Moxie Marlinspike](http://www.thoughtcrime.org/) to allow
+pinning of server certificates, improving security against government-scale
+MitM attacks. Use this if your app is made to communicate with a specific
+server!
+
+## Contribute
+
+Please [help translating MTM into more languages](https://translations.launchpad.net/yaxim/master/+pots/mtm/)!
A libs/MemorizingTrustManager/ant.properties => libs/MemorizingTrustManager/ant.properties +17 -0
@@ 0,0 1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
A libs/MemorizingTrustManager/build.gradle => libs/MemorizingTrustManager/build.gradle +32 -0
@@ 0,0 1,32 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.7.+'
+ }
+}
+
+apply plugin: 'android-library'
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "19.1"
+ defaultConfig {
+ minSdkVersion 7
+ targetSdkVersion 19
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['assets']
+ }
+ }
+
+}
R build.xml => libs/MemorizingTrustManager/build.xml +1 -1
@@ 1,5 1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project name="Conversations" default="help">
+<project name="MemorizingTrustManager" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
A libs/MemorizingTrustManager/example/AndroidManifest.xml => libs/MemorizingTrustManager/example/AndroidManifest.xml +29 -0
@@ 0,0 1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.duenndns.mtmexample"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk
+ android:minSdkVersion="3"
+ android:targetSdkVersion="19" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:label="@string/app_name" android:icon="@android:drawable/ic_lock_lock">
+ <activity
+ android:name=".MTMExample"
+ android:configChanges="keyboardHidden|orientation|screenSize|screenLayout"
+ android:label="@string/app_name" >
+
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- ADD THE FOLLOWING TO YOUR MANIFEST: -->
+ <activity android:name="de.duenndns.ssl.MemorizingActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+ </application>
+</manifest>
A libs/MemorizingTrustManager/example/ant.properties => libs/MemorizingTrustManager/example/ant.properties +18 -0
@@ 0,0 1,18 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+application.package=de.duenndns.mtmexample
A libs/MemorizingTrustManager/example/build.gradle => libs/MemorizingTrustManager/example/build.gradle +23 -0
@@ 0,0 1,23 @@
+apply plugin: 'android'
+
+dependencies {
+ compile rootProject
+}
+
+android {
+ compileSdkVersion 19
+ buildToolsVersion "19.1"
+ defaultConfig {
+ minSdkVersion 7
+ targetSdkVersion 19
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ res.srcDirs = ['res']
+ }
+ }
+
+}
A libs/MemorizingTrustManager/example/build.xml => libs/MemorizingTrustManager/example/build.xml +92 -0
@@ 0,0 1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="MTMExample" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The ant.properties file can be created by you. It is only edited by the
+ 'android' tool to add properties to it.
+ This is the place to change some Ant specific build properties.
+ Here are some properties you may want to change/update:
+
+ source.dir
+ The name of the source directory. Default is 'src'.
+ out.dir
+ The name of the output directory. Default is 'bin'.
+
+ For other overridable properties, look at the beginning of the rules
+ files in the SDK, at tools/ant/build.xml
+
+ Properties related to the SDK location or the project target should
+ be updated using the 'android' tool with the 'update' action.
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems.
+
+ -->
+ <property file="ant.properties" />
+
+ <!-- if sdk.dir was not set from one of the property file, then
+ get it from the ANDROID_HOME env var.
+ This must be done before we load project.properties since
+ the proguard config can use sdk.dir -->
+ <property environment="env" />
+ <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+ <isset property="env.ANDROID_HOME" />
+ </condition>
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
A libs/MemorizingTrustManager/example/proguard-project.txt => libs/MemorizingTrustManager/example/proguard-project.txt +20 -0
@@ 0,0 1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
A libs/MemorizingTrustManager/example/project.properties => libs/MemorizingTrustManager/example/project.properties +12 -0
@@ 0,0 1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+android.library.reference.1=../
+# Project target.
+target=android-19
A libs/MemorizingTrustManager/example/res/layout/mtmexample.xml => libs/MemorizingTrustManager/example/res/layout/mtmexample.xml +36 -0
@@ 0,0 1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ <EditText
+ android:id="@+id/url"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:hint="HTTPS address"
+ android:text="https://op-co.de/mtm/"
+ android:singleLine="true"
+ />
+ <Button
+ android:id="@+id/connect"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Connect"
+ />
+ <TextView
+ android:id="@+id/content"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Please enter a HTTPS URL and press 'Connect'!"
+ android:textSize="11pt"
+ />
+ <Button
+ android:id="@+id/manage"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="Clean up Certificates"
+ android:onClick="onManage"
+ />
+</LinearLayout>
+
A libs/MemorizingTrustManager/example/res/values/strings.xml => libs/MemorizingTrustManager/example/res/values/strings.xml +4 -0
@@ 0,0 1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">MemorizingTrustManager Example</string>
+</resources>
A libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java => libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/JULHandler.java +169 -0
@@ 0,0 1,169 @@
+package de.duenndns.mtmexample;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringBufferInputStream;
+import java.io.StringWriter;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import android.util.Log;
+
+/**
+ * A <code>java.util.logging</code> (JUL) Handler for Android.
+ * <p>
+ * If you want fine-grained control over MTM's logging, you can copy this
+ * class to your code base and call the static {@link #initialize()} method.
+ * </p>
+ * <p>
+ * This JUL Handler passes log messages sent to JUL to the Android log, while
+ * keeping the format and stack traces of optionally supplied Exceptions. It
+ * further allows to install a {@link DebugLogSettings} class via
+ * {@link #setDebugLogSettings(DebugLogSettings)} that determines whether JUL log messages of
+ * level {@link java.util.logging.Level#FINE} or lower are logged. This gives
+ * the application developer more control over the logged messages, while
+ * allowing a library developer to place debug log messages without risking to
+ * spam the Android log.
+ * </p>
+ * <p>
+ * If there are no {@code DebugLogSettings} configured, then all messages sent
+ * to JUL will be logged.
+ * </p>
+ *
+ * @author Florian Schmaus
+ *
+ */
+@SuppressWarnings("deprecation")
+public class JULHandler extends Handler {
+
+ /** Implement this interface to toggle debug logging.
+ */
+ public interface DebugLogSettings {
+ public boolean isDebugLogEnabled();
+ }
+
+ private static final String CLASS_NAME = JULHandler.class.getName();
+
+ /**
+ * The global LogManager configuration.
+ * <p>
+ * This configures:
+ * <ul>
+ * <li> JULHandler as the default handler for all log messages
+ * <li> A default log level FINEST (300). Meaning that log messages of a level 300 or higher a
+ * logged
+ * </ul>
+ * </p>
+ */
+ private static final InputStream LOG_MANAGER_CONFIG = new StringBufferInputStream(
+// @formatter:off
+"handlers = " + CLASS_NAME + '\n' +
+".level = FINEST"
+);
+// @formatter:on
+
+ // Constants for Android vs. JUL debug level comparisons
+ private static final int FINE_INT = Level.FINE.intValue();
+ private static final int INFO_INT = Level.INFO.intValue();
+ private static final int WARN_INT = Level.WARNING.intValue();
+ private static final int SEVE_INT = Level.SEVERE.intValue();
+
+ private static final Logger LOGGER = Logger.getLogger(CLASS_NAME);
+
+ /** A formatter that creates output similar to Android's Log.x. */
+ private static final Formatter FORMATTER = new Formatter() {
+ @Override
+ public String format(LogRecord logRecord) {
+ Throwable thrown = logRecord.getThrown();
+ if (thrown != null) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, false);
+ pw.write(logRecord.getMessage() + ' ');
+ thrown.printStackTrace(pw);
+ pw.flush();
+ return sw.toString();
+ } else {
+ return logRecord.getMessage();
+ }
+ }
+ };
+
+ private static DebugLogSettings sDebugLogSettings;
+ private static boolean initialized = false;
+
+ public static void initialize() {
+ try {
+ LogManager.getLogManager().readConfiguration(LOG_MANAGER_CONFIG);
+ initialized = true;
+ } catch (IOException e) {
+ Log.e("JULHandler", "Can not initialize configuration", e);
+ }
+ if (initialized) LOGGER.info("Initialzied java.util.logging logger");
+ }
+
+ public static void setDebugLogSettings(DebugLogSettings debugLogSettings) {
+ if (!isInitialized()) initialize();
+ sDebugLogSettings = debugLogSettings;
+ }
+
+ public static boolean isInitialized() {
+ return initialized;
+ }
+
+ public JULHandler() {
+ setFormatter(FORMATTER);
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public boolean isLoggable(LogRecord record) {
+ final boolean debugLog = sDebugLogSettings == null ? true : sDebugLogSettings
+ .isDebugLogEnabled();
+
+ if (record.getLevel().intValue() <= FINE_INT) {
+ return debugLog;
+ }
+ return true;
+ }
+
+ /** JUL method that forwards log records to Android's LogCat. */
+ @Override
+ public void publish(LogRecord record) {
+ if (!isLoggable(record)) return;
+
+ final int priority = getAndroidPriority(record.getLevel());
+ final String tag = substringAfterLastDot(record.getSourceClassName());
+ final String msg = getFormatter().format(record);
+
+ Log.println(priority, tag, msg);
+ }
+
+ /** Helper to convert JUL verbosity levels to Android's Log. */
+ private static int getAndroidPriority(Level level) {
+ int value = level.intValue();
+ if (value >= SEVE_INT) {
+ return Log.ERROR;
+ } else if (value >= WARN_INT) {
+ return Log.WARN;
+ } else if (value >= INFO_INT) {
+ return Log.INFO;
+ } else {
+ return Log.DEBUG;
+ }
+ }
+
+ /** Helper to extract short class names. */
+ private static String substringAfterLastDot(String s) {
+ return s.substring(s.lastIndexOf('.') + 1).trim();
+ }
+}
A libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java => libs/MemorizingTrustManager/example/src/de/duenndns/mtmexample/MTMExample.java +143 -0
@@ 0,0 1,143 @@
+package de.duenndns.mtmexample;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.net.URL;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.X509TrustManager;
+
+import de.duenndns.ssl.MemorizingTrustManager;
+
+/**
+ * Example to demonstrate the use of MemorizingTrustManager on HTTPS
+ * sockets.
+ */
+public class MTMExample extends Activity implements OnClickListener
+{
+ MemorizingTrustManager mtm;
+
+ TextView content;
+ HostnameVerifier defaultverifier;
+ EditText urlinput;
+ String text;
+ Handler hdlr;
+
+ /** Creates the Activity and registers a MemorizingTrustManager. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ JULHandler.initialize();
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setContentView(R.layout.mtmexample);
+
+
+ // set up gui elements
+ findViewById(R.id.connect).setOnClickListener(this);
+ content = (TextView)findViewById(R.id.content);
+ urlinput = (EditText)findViewById(R.id.url);
+
+ // register handler for background thread
+ hdlr = new Handler();
+
+ // Here, the MemorizingTrustManager is activated for HTTPS
+ try {
+ // set location of the keystore
+ MemorizingTrustManager.setKeyStoreFile("private", "sslkeys.bks");
+
+ // register MemorizingTrustManager for HTTPS
+ SSLContext sc = SSLContext.getInstance("TLS");
+ mtm = new MemorizingTrustManager(this);
+ sc.init(null, new X509TrustManager[] { mtm },
+ new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(
+ mtm.wrapHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()));
+
+ // disable redirects to reduce possible confusion
+ HttpsURLConnection.setFollowRedirects(false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Updates the screen content from a background thread. */
+ void setText(final String s, final boolean progress) {
+ text = s;
+ hdlr.post(new Runnable() {
+ public void run() {
+ content.setText(s);
+ setProgressBarIndeterminateVisibility(progress);
+ }
+ });
+ }
+
+ /** Spawns a new thread connecting to the specified URL.
+ * The result of the request is displayed on the screen.
+ * @param urlString a HTTPS URL to connect to.
+ */
+ void connect(final String urlString) {
+ new Thread() {
+ public void run() {
+ try {
+ URL u = new URL(urlString);
+ HttpsURLConnection c = (HttpsURLConnection)u.openConnection();
+ c.connect();
+ setText("" + c.getResponseCode() + " "
+ + c.getResponseMessage(), false);
+ c.disconnect();
+ } catch (Exception e) {
+ setText(e.toString(), false);
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
+
+ /** Reacts on the connect Button press. */
+ @Override
+ public void onClick(View view) {
+ String url = urlinput.getText().toString();
+ setText("Loading " + url, true);
+ setProgressBarIndeterminateVisibility(true);
+ connect(url);
+ }
+
+ /** React on the "Manage Certificates" button press. */
+ public void onManage(View view) {
+ final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.select_dialog_item, aliases);
+ new AlertDialog.Builder(this).setTitle("Tap Certificate to Delete")
+ .setNegativeButton(android.R.string.cancel, null)
+ .setAdapter(adapter, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ String alias = aliases.get(which);
+ mtm.deleteCertificate(alias);
+ setText("Deleted " + alias, false);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ setText("Error: " + e.getLocalizedMessage(), false);
+ }
+ }
+ })
+ .create().show();
+ }
+}
A libs/MemorizingTrustManager/libs/.android_sucks => libs/MemorizingTrustManager/libs/.android_sucks +0 -0
A libs/MemorizingTrustManager/mtm-notification.png => libs/MemorizingTrustManager/mtm-notification.png +0 -0
A libs/MemorizingTrustManager/mtm-screenshot.png => libs/MemorizingTrustManager/mtm-screenshot.png +0 -0
A libs/MemorizingTrustManager/mtm-servername.png => libs/MemorizingTrustManager/mtm-servername.png +0 -0
A libs/MemorizingTrustManager/proguard-project.txt => libs/MemorizingTrustManager/proguard-project.txt +20 -0
@@ 0,0 1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
A libs/MemorizingTrustManager/project.properties => libs/MemorizingTrustManager/project.properties +12 -0
@@ 0,0 1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+android.library=true
+# Project target.
+target=android-19
A libs/MemorizingTrustManager/res/values-de/strings.xml => libs/MemorizingTrustManager/res/values-de/strings.xml +17 -0
@@ 0,0 1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Unbekanntes Zertifikat akzeptieren?</string>
+ <string name="mtm_trust_anchor">Das Serverzertifikat stammt nicht von einer bekannten Ausstellungsstelle (CA).</string>
+ <string name="mtm_cert_expired">The server certificate is expired.</string>
+ <string name="mtm_accept_servername">Abweichenden Servernamen akzeptieren?</string>
+ <string name="mtm_hostname_mismatch">Der Server konnte sich nicht als \"%s\" ausweisen. Das Zertifikat gilt nur für:</string>
+
+ <string name="mtm_connect_anyway">Verbindung trotzdem aufbauen?</string>
+ <string name="mtm_cert_details">Zertifikat-Details:</string>
+
+ <string name="mtm_decision_always">Immer</string>
+ <string name="mtm_decision_once">Einmal</string>
+ <string name="mtm_decision_abort">Abbrechen</string>
+
+ <string name="mtm_notification">Zertifikatsprüfung</string>
+</resources>
A libs/MemorizingTrustManager/res/values-es/strings.xml => libs/MemorizingTrustManager/res/values-es/strings.xml +17 -0
@@ 0,0 1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">¿Aceptar certicado desconocido?</string>
+ <string name="mtm_trust_anchor">El certificado del servidor no está firmado por una Autoridad Conocida (CA).</string>
+ <string name="mtm_cert_expired">The server certificate is expired.</string>
+ <string name="mtm_accept_servername">¿Aceptar discordancia en nombre del servidor?</string>
+ <string name="mtm_hostname_mismatch">El servidor no ha podido autenticarte como \"%s\". El certificado es solo válido para:</string>
+
+ <string name="mtm_connect_anyway">¿Quieres conectar de todas formas?</string>
+ <string name="mtm_cert_details">Detalle del certificado:</string>
+
+ <string name="mtm_decision_always">Siempre</string>
+ <string name="mtm_decision_once">Una vez</string>
+ <string name="mtm_decision_abort">Abortar</string>
+
+ <string name="mtm_notification">Verificación de Certificado</string>
+</resources>
A libs/MemorizingTrustManager/res/values-eu/strings.xml => libs/MemorizingTrustManager/res/values-eu/strings.xml +17 -0
@@ 0,0 1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Ziurtagiri ezezaguna onartu?</string>
+ <string name="mtm_trust_anchor">Zerbitzariaren ziurtagiria ez dago Ziurtagiri-emaile Autoritate ezagun batez sinatuta.</string>
+ <string name="mtm_cert_expired">Zerbitzariaren ziurtagiria iraungi da.</string>
+ <string name="mtm_accept_servername">Zerbitzariaren izeneko desadostasuna onartu?</string>
+ <string name="mtm_hostname_mismatch">Zerbitzaria ezin izan da \"%s\" bezala autentifikatu. Ziurtagiria soilik honetarako baliagarria da:</string>
+
+ <string name="mtm_connect_anyway">Konektatu hala ere?</string>
+ <string name="mtm_cert_details">Ziurtagiriaren xehetasunak:</string>
+
+ <string name="mtm_decision_always">Beti</string>
+ <string name="mtm_decision_once">Behin</string>
+ <string name="mtm_decision_abort">Utzi</string>
+
+ <string name="mtm_notification">Ziurtagiriaren egiaztapena</string>
+</resources>
A libs/MemorizingTrustManager/res/values-fi/strings.xml => libs/MemorizingTrustManager/res/values-fi/strings.xml +16 -0
@@ 0,0 1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Hyväksytäänkö palvelimen antama tuntematon varmenne?</string>
+ <string name="mtm_trust_anchor">Palvelimen varmenne ei ole tunnetun varmentajan (CA) allekirjoittama.</string>
+ <string name="mtm_accept_servername">Sallitaanko palvelimen nimi, joka ei vastaa varmeenteessa olevaa nimeä?</string>
+ <string name="mtm_hostname_mismatch">Palvelimella ei ole varmennetta nimelle \"%s\". Varmenteen sisältämät nimet:</string>
+
+ <string name="mtm_connect_anyway">Haluatko jatkaa yhteyden muodostamista?</string>
+ <string name="mtm_cert_details">Sertifikaatin tiedot:</string>
+
+ <string name="mtm_decision_always">Aina</string>
+ <string name="mtm_decision_once">Kerran</string>
+ <string name="mtm_decision_abort">Keskeytä</string>
+
+ <string name="mtm_notification">Varmenteen tarkistus</string>
+</resources>
A libs/MemorizingTrustManager/res/values-fr/strings.xml => libs/MemorizingTrustManager/res/values-fr/strings.xml +16 -0
@@ 0,0 1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Accept Unknown Certificate?</string>
+ <string name="mtm_trust_anchor">Le certificat du serveur n’est pas signé par une Autorité de Certification reconnue.</string>
+ <string name="mtm_accept_servername">Accept Mismatching Server Name?</string>
+ <string name="mtm_hostname_mismatch">Server could not authenticate as \"%s\". The certificate is only valid for:</string>
+
+ <string name="mtm_connect_anyway">Do you want to connect anyway?</string>
+ <string name="mtm_cert_details">Détails du certificat :</string>
+
+ <string name="mtm_decision_always">Toujours</string>
+ <string name="mtm_decision_once">Une seule fois</string>
+ <string name="mtm_decision_abort">Annuler</string>
+
+ <string name="mtm_notification">Certificate Verification</string>
+</resources>
A libs/MemorizingTrustManager/res/values-no/strings.xml => libs/MemorizingTrustManager/res/values-no/strings.xml +16 -0
@@ 0,0 1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Godta ukjent sertifikat?</string>
+ <string name="mtm_trust_anchor">Sertifikatet er ikke utstilt av en kjent utstiller (CA).</string>
+ <string name="mtm_accept_servername">Godta feil servernavn?</string>
+ <string name="mtm_hostname_mismatch">Serveren heter ikke \"%s\". Sertifikatet gjelder bare for: </string>
+
+ <string name="mtm_connect_anyway">Vil du bruke serveren likevel?</string>
+ <string name="mtm_cert_details">Sertifikatdetaljer:</string>
+
+ <string name="mtm_decision_always">Alltid</string>
+ <string name="mtm_decision_once">En gang</string>
+ <string name="mtm_decision_abort">Avbryt</string>
+
+ <string name="mtm_notification">Sertifikat-sjekk</string>
+</resources>
A libs/MemorizingTrustManager/res/values/strings.xml => libs/MemorizingTrustManager/res/values/strings.xml +17 -0
@@ 0,0 1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mtm_accept_cert">Accept Unknown Certificate?</string>
+ <string name="mtm_trust_anchor">The server certificate is not signed by a known Certificate Authority.</string>
+ <string name="mtm_cert_expired">The server certificate is expired.</string>
+ <string name="mtm_accept_servername">Accept Mismatching Server Name?</string>
+ <string name="mtm_hostname_mismatch">Server could not authenticate as \"%s\". The certificate is only valid for:</string>
+
+ <string name="mtm_connect_anyway">Do you want to connect anyway?</string>
+ <string name="mtm_cert_details">Certificate details:</string>
+
+ <string name="mtm_decision_always">Always</string>
+ <string name="mtm_decision_once">Once</string>
+ <string name="mtm_decision_abort">Abort</string>
+
+ <string name="mtm_notification">Certificate Verification</string>
+</resources>
A libs/MemorizingTrustManager/settings.gradle => libs/MemorizingTrustManager/settings.gradle +1 -0
@@ 0,0 1,1 @@
+include ':example'
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MTMDecision.java => libs/MemorizingTrustManager/src/de/duenndns/ssl/MTMDecision.java +33 -0
@@ 0,0 1,33 @@
+/* MemorizingTrustManager - a TrustManager which asks the user about invalid
+ * certificates and memorizes their decision.
+ *
+ * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package de.duenndns.ssl;
+
+class MTMDecision {
+ public final static int DECISION_INVALID = 0;
+ public final static int DECISION_ABORT = 1;
+ public final static int DECISION_ONCE = 2;
+ public final static int DECISION_ALWAYS = 3;
+
+ int state = DECISION_INVALID;
+}
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingActivity.java => libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingActivity.java +103 -0
@@ 0,0 1,103 @@
+/* MemorizingTrustManager - a TrustManager which asks the user about invalid
+ * certificates and memorizes their decision.
+ *
+ * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package de.duenndns.ssl;
+
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.*;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class MemorizingActivity extends Activity
+ implements OnClickListener,OnCancelListener {
+
+ private final static Logger LOGGER = Logger.getLogger(MemorizingActivity.class.getName());
+
+ int decisionId;
+
+ AlertDialog dialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ LOGGER.log(Level.FINE, "onCreate");
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Intent i = getIntent();
+ decisionId = i.getIntExtra(MemorizingTrustManager.DECISION_INTENT_ID, MTMDecision.DECISION_INVALID);
+ int titleId = i.getIntExtra(MemorizingTrustManager.DECISION_TITLE_ID, R.string.mtm_accept_cert);
+ String cert = i.getStringExtra(MemorizingTrustManager.DECISION_INTENT_CERT);
+ LOGGER.log(Level.FINE, "onResume with " + i.getExtras() + " decId=" + decisionId + " data: " + i.getData());
+ dialog = new AlertDialog.Builder(this).setTitle(titleId)
+ .setMessage(cert)
+ .setPositiveButton(R.string.mtm_decision_always, this)
+ .setNeutralButton(R.string.mtm_decision_once, this)
+ .setNegativeButton(R.string.mtm_decision_abort, this)
+ .setOnCancelListener(this)
+ .create();
+ dialog.show();
+ }
+
+ @Override
+ protected void onPause() {
+ if (dialog.isShowing())
+ dialog.dismiss();
+ super.onPause();
+ }
+
+ void sendDecision(int decision) {
+ LOGGER.log(Level.FINE, "Sending decision: " + decision);
+ MemorizingTrustManager.interactResult(decisionId, decision);
+ finish();
+ }
+
+ // react on AlertDialog button press
+ public void onClick(DialogInterface dialog, int btnId) {
+ int decision;
+ dialog.dismiss();
+ switch (btnId) {
+ case DialogInterface.BUTTON_POSITIVE:
+ decision = MTMDecision.DECISION_ALWAYS;
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ decision = MTMDecision.DECISION_ONCE;
+ break;
+ default:
+ decision = MTMDecision.DECISION_ABORT;
+ }
+ sendDecision(decision);
+ }
+
+ public void onCancel(DialogInterface dialog) {
+ sendDecision(MTMDecision.DECISION_ABORT);
+ }
+}
A libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java => libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java +735 -0
@@ 0,0 1,735 @@
+/* MemorizingTrustManager - a TrustManager which asks the user about invalid
+ * certificates and memorizes their decision.
+ *
+ * Copyright (c) 2010 Georg Lukas <georg@op-co.de>
+ *
+ * MemorizingTrustManager.java contains the actual trust manager and interface
+ * code to create a MemorizingActivity and obtain the results.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package de.duenndns.ssl;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.SparseArray;
+import android.os.Handler;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.cert.*;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.MessageDigest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * A X509 trust manager implementation which asks the user about invalid
+ * certificates and memorizes their decision.
+ * <p>
+ * The certificate validity is checked using the system default X509
+ * TrustManager, creating a query Dialog if the check fails.
+ * <p>
+ * <b>WARNING:</b> This only works if a dedicated thread is used for
+ * opening sockets!
+ */
+public class MemorizingTrustManager implements X509TrustManager {
+ final static String DECISION_INTENT = "de.duenndns.ssl.DECISION";
+ final static String DECISION_INTENT_ID = DECISION_INTENT + ".decisionId";
+ final static String DECISION_INTENT_CERT = DECISION_INTENT + ".cert";
+ final static String DECISION_INTENT_CHOICE = DECISION_INTENT + ".decisionChoice";
+
+ private final static Logger LOGGER = Logger.getLogger(MemorizingTrustManager.class.getName());
+ final static String DECISION_TITLE_ID = DECISION_INTENT + ".titleId";
+ private final static int NOTIFICATION_ID = 100509;
+
+ final static String NO_TRUST_ANCHOR = "Trust anchor for certification path not found.";
+
+ static String KEYSTORE_DIR = "KeyStore";
+ static String KEYSTORE_FILE = "KeyStore.bks";
+
+ Context master;
+ Activity foregroundAct;
+ NotificationManager notificationManager;
+ private static int decisionId = 0;
+ private static SparseArray<MTMDecision> openDecisions = new SparseArray<MTMDecision>();
+
+ Handler masterHandler;
+ private File keyStoreFile;
+ private KeyStore appKeyStore;
+ private X509TrustManager defaultTrustManager;
+ private X509TrustManager appTrustManager;
+
+ /** Creates an instance of the MemorizingTrustManager class that falls back to a custom TrustManager.
+ *
+ * You need to supply the application context. This has to be one of:
+ * - Application
+ * - Activity
+ * - Service
+ *
+ * The context is used for file management, to display the dialog /
+ * notification and for obtaining translated strings.
+ *
+ * @param m Context for the application.
+ * @param defaultTrustManager Delegate trust management to this TM. If null, the user must accept every certificate.
+ */
+ public MemorizingTrustManager(Context m, X509TrustManager defaultTrustManager) {
+ init(m);
+ this.appTrustManager = getTrustManager(appKeyStore);
+ this.defaultTrustManager = defaultTrustManager;
+ }
+
+ /** Creates an instance of the MemorizingTrustManager class using the system X509TrustManager.
+ *
+ * You need to supply the application context. This has to be one of:
+ * - Application
+ * - Activity
+ * - Service
+ *
+ * The context is used for file management, to display the dialog /
+ * notification and for obtaining translated strings.
+ *
+ * @param m Context for the application.
+ */
+ public MemorizingTrustManager(Context m) {
+ init(m);
+ this.appTrustManager = getTrustManager(appKeyStore);
+ this.defaultTrustManager = getTrustManager(null);
+ }
+
+ void init(Context m) {
+ master = m;
+ masterHandler = new Handler(m.getMainLooper());
+ notificationManager = (NotificationManager)master.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ Application app;
+ if (m instanceof Application) {
+ app = (Application)m;
+ } else if (m instanceof Service) {
+ app = ((Service)m).getApplication();
+ } else if (m instanceof Activity) {
+ app = ((Activity)m).getApplication();
+ } else throw new ClassCastException("MemorizingTrustManager context must be either Activity or Service!");
+
+ File dir = app.getDir(KEYSTORE_DIR, Context.MODE_PRIVATE);
+ keyStoreFile = new File(dir + File.separator + KEYSTORE_FILE);
+
+ appKeyStore = loadAppKeyStore();
+ }
+
+
+ /**
+ * Returns a X509TrustManager list containing a new instance of
+ * TrustManagerFactory.
+ *
+ * This function is meant for convenience only. You can use it
+ * as follows to integrate TrustManagerFactory for HTTPS sockets:
+ *
+ * <pre>
+ * SSLContext sc = SSLContext.getInstance("TLS");
+ * sc.init(null, MemorizingTrustManager.getInstanceList(this),
+ * new java.security.SecureRandom());
+ * HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ * </pre>
+ * @param c Activity or Service to show the Dialog / Notification
+ */
+ public static X509TrustManager[] getInstanceList(Context c) {
+ return new X509TrustManager[] { new MemorizingTrustManager(c) };
+ }
+
+ /**
+ * Binds an Activity to the MTM for displaying the query dialog.
+ *
+ * This is useful if your connection is run from a service that is
+ * triggered by user interaction -- in such cases the activity is
+ * visible and the user tends to ignore the service notification.
+ *
+ * You should never have a hidden activity bound to MTM! Use this
+ * function in onResume() and @see unbindDisplayActivity in onPause().
+ *
+ * @param act Activity to be bound
+ */
+ public void bindDisplayActivity(Activity act) {
+ foregroundAct = act;
+ }
+
+ /**
+ * Removes an Activity from the MTM display stack.
+ *
+ * Always call this function when the Activity added with
+ * {@link #bindDisplayActivity(Activity)} is hidden.
+ *
+ * @param act Activity to be unbound
+ */
+ public void unbindDisplayActivity(Activity act) {
+ // do not remove if it was overridden by a different activity
+ if (foregroundAct == act)
+ foregroundAct = null;
+ }
+
+ /**
+ * Changes the path for the KeyStore file.
+ *
+ * The actual filename relative to the app's directory will be
+ * <code>app_<i>dirname</i>/<i>filename</i></code>.
+ *
+ * @param dirname directory to store the KeyStore.
+ * @param filename file name for the KeyStore.
+ */
+ public static void setKeyStoreFile(String dirname, String filename) {
+ KEYSTORE_DIR = dirname;
+ KEYSTORE_FILE = filename;
+ }
+
+ /**
+ * Get a list of all certificate aliases stored in MTM.
+ *
+ * @return an {@link Enumeration} of all certificates
+ */
+ public Enumeration<String> getCertificates() {
+ try {
+ return appKeyStore.aliases();
+ } catch (KeyStoreException e) {
+ // this should never happen, however...
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Get a certificate for a given alias.
+ *
+ * @param alias the certificate's alias as returned by {@link #getCertificates()}.
+ *
+ * @return the certificate associated with the alias or <tt>null</tt> if none found.
+ */
+ public Certificate getCertificate(String alias) {
+ try {
+ return appKeyStore.getCertificate(alias);
+ } catch (KeyStoreException e) {
+ // this should never happen, however...
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Removes the given certificate from MTMs key store.
+ *
+ * <p>
+ * <b>WARNING</b>: this does not immediately invalidate the certificate. It is
+ * well possible that (a) data is transmitted over still existing connections or
+ * (b) new connections are created using TLS renegotiation, without a new cert
+ * check.
+ * </p>
+ * @param alias the certificate's alias as returned by {@link #getCertificates()}.
+ *
+ * @throws KeyStoreException if the certificate could not be deleted.
+ */
+ public void deleteCertificate(String alias) throws KeyStoreException {
+ appKeyStore.deleteEntry(alias);
+ keyStoreUpdated();
+ }
+
+ /**
+ * Creates a new hostname verifier supporting user interaction.
+ *
+ * <p>This method creates a new {@link HostnameVerifier} that is bound to
+ * the given instance of {@link MemorizingTrustManager}, and leverages an
+ * existing {@link HostnameVerifier}. The returned verifier performs the
+ * following steps, returning as soon as one of them succeeds:
+ * </p>
+ * <ol>
+ * <li>Success, if the wrapped defaultVerifier accepts the certificate.</li>
+ * <li>Success, if the server certificate is stored in the keystore under the given hostname.</li>
+ * <li>Ask the user and return accordingly.</li>
+ * <li>Failure on exception.</li>
+ * </ol>
+ *
+ * @param defaultVerifier the {@link HostnameVerifier} that should perform the actual check
+ * @return a new hostname verifier using the MTM's key store
+ *
+ * @throws IllegalArgumentException if the defaultVerifier parameter is null
+ */
+ public HostnameVerifier wrapHostnameVerifier(final HostnameVerifier defaultVerifier) {
+ if (defaultVerifier == null)
+ throw new IllegalArgumentException("The default verifier may not be null");
+
+ return new MemorizingHostnameVerifier(defaultVerifier);
+ }
+
+ public HostnameVerifier wrapHostnameVerifierNonInteractive(final HostnameVerifier defaultVerifier) {
+ if (defaultVerifier == null)
+ throw new IllegalArgumentException("The default verifier may not be null");
+
+ return new NonInteractiveMemorizingHostnameVerifier(defaultVerifier);
+ }
+
+ X509TrustManager getTrustManager(KeyStore ks) {
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
+ tmf.init(ks);
+ for (TrustManager t : tmf.getTrustManagers()) {
+ if (t instanceof X509TrustManager) {
+ return (X509TrustManager)t;
+ }
+ }
+ } catch (Exception e) {
+ // Here, we are covering up errors. It might be more useful
+ // however to throw them out of the constructor so the
+ // embedding app knows something went wrong.
+ LOGGER.log(Level.SEVERE, "getTrustManager(" + ks + ")", e);
+ }
+ return null;
+ }
+
+ KeyStore loadAppKeyStore() {
+ KeyStore ks;
+ try {
+ ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ LOGGER.log(Level.SEVERE, "getAppKeyStore()", e);
+ return null;
+ }
+ try {
+ ks.load(null, null);
+ ks.load(new java.io.FileInputStream(keyStoreFile), "MTM".toCharArray());
+ } catch (java.io.FileNotFoundException e) {
+ LOGGER.log(Level.INFO, "getAppKeyStore(" + keyStoreFile + ") - file does not exist");
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE, "getAppKeyStore(" + keyStoreFile + ")", e);
+ }
+ return ks;
+ }
+
+ void storeCert(String alias, Certificate cert) {
+ try {
+ appKeyStore.setCertificateEntry(alias, cert);
+ } catch (KeyStoreException e) {
+ LOGGER.log(Level.SEVERE, "storeCert(" + cert + ")", e);
+ return;
+ }
+ keyStoreUpdated();
+ }
+
+ void storeCert(X509Certificate cert) {
+ storeCert(cert.getSubjectDN().toString(), cert);
+ }
+
+ void keyStoreUpdated() {
+ // reload appTrustManager
+ appTrustManager = getTrustManager(appKeyStore);
+
+ // store KeyStore to file
+ java.io.FileOutputStream fos = null;
+ try {
+ fos = new java.io.FileOutputStream(keyStoreFile);
+ appKeyStore.store(fos, "MTM".toCharArray());
+ } catch (Exception e) {
+ LOGGER.log(Level.SEVERE, "storeCert(" + keyStoreFile + ")", e);
+ } finally {
+ if (fos != null) {
+ try {
+ fos.close();
+ } catch (IOException e) {
+ LOGGER.log(Level.SEVERE, "storeCert(" + keyStoreFile + ")", e);
+ }
+ }
+ }
+ }
+
+ // if the certificate is stored in the app key store, it is considered "known"
+ private boolean isCertKnown(X509Certificate cert) {
+ try {
+ return appKeyStore.getCertificateAlias(cert) != null;
+ } catch (KeyStoreException e) {
+ return false;
+ }
+ }
+
+ private boolean isExpiredException(Throwable e) {
+ do {
+ if (e instanceof CertificateExpiredException)
+ return true;
+ e = e.getCause();
+ } while (e != null);
+ return false;
+ }
+
+ public void checkCertTrusted(X509Certificate[] chain, String authType, boolean isServer, boolean interactive)
+ throws CertificateException
+ {
+ LOGGER.log(Level.FINE, "checkCertTrusted(" + chain + ", " + authType + ", " + isServer + ")");
+ try {
+ LOGGER.log(Level.FINE, "checkCertTrusted: trying appTrustManager");
+ if (isServer)
+ appTrustManager.checkServerTrusted(chain, authType);
+ else
+ appTrustManager.checkClientTrusted(chain, authType);
+ } catch (CertificateException ae) {
+ LOGGER.log(Level.FINER, "checkCertTrusted: appTrustManager failed", ae);
+ // if the cert is stored in our appTrustManager, we ignore expiredness
+ if (isExpiredException(ae)) {
+ LOGGER.log(Level.INFO, "checkCertTrusted: accepting expired certificate from keystore");
+ return;
+ }
+ if (isCertKnown(chain[0])) {
+ LOGGER.log(Level.INFO, "checkCertTrusted: accepting cert already stored in keystore");
+ return;
+ }
+ try {
+ if (defaultTrustManager == null)
+ throw ae;
+ LOGGER.log(Level.FINE, "checkCertTrusted: trying defaultTrustManager");
+ if (isServer)
+ defaultTrustManager.checkServerTrusted(chain, authType);
+ else
+ defaultTrustManager.checkClientTrusted(chain, authType);
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ if (interactive) {
+ interactCert(chain, authType, e);
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ checkCertTrusted(chain, authType, false,true);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ checkCertTrusted(chain, authType, true,true);
+ }
+
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ LOGGER.log(Level.FINE, "getAcceptedIssuers()");
+ return defaultTrustManager.getAcceptedIssuers();
+ }
+
+ private int createDecisionId(MTMDecision d) {
+ int myId;
+ synchronized(openDecisions) {
+ myId = decisionId;
+ openDecisions.put(myId, d);
+ decisionId += 1;
+ }
+ return myId;
+ }
+
+ private static String hexString(byte[] data) {
+ StringBuffer si = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ si.append(String.format("%02x", data[i]));
+ if (i < data.length - 1)
+ si.append(":");
+ }
+ return si.toString();
+ }
+
+ private static String certHash(final X509Certificate cert, String digest) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(digest);
+ md.update(cert.getEncoded());
+ return hexString(md.digest());
+ } catch (java.security.cert.CertificateEncodingException e) {
+ return e.getMessage();
+ } catch (java.security.NoSuchAlgorithmException e) {
+ return e.getMessage();
+ }
+ }
+
+ private void certDetails(StringBuffer si, X509Certificate c) {
+ SimpleDateFormat validityDateFormater = new SimpleDateFormat("yyyy-MM-dd");
+ si.append("\n");
+ si.append(c.getSubjectDN().toString());
+ si.append("\n");
+ si.append(validityDateFormater.format(c.getNotBefore()));
+ si.append(" - ");
+ si.append(validityDateFormater.format(c.getNotAfter()));
+ si.append("\nSHA-256: ");
+ si.append(certHash(c, "SHA-256"));
+ si.append("\nSHA-1: ");
+ si.append(certHash(c, "SHA-1"));
+ si.append("\nSigned by: ");
+ si.append(c.getIssuerDN().toString());
+ si.append("\n");
+ }
+
+ private String certChainMessage(final X509Certificate[] chain, CertificateException cause) {
+ Throwable e = cause;
+ LOGGER.log(Level.FINE, "certChainMessage for " + e);
+ StringBuffer si = new StringBuffer();
+ if (e.getCause() != null) {
+ e = e.getCause();
+ // HACK: there is no sane way to check if the error is a "trust anchor
+ // not found", so we use string comparison.
+ if (NO_TRUST_ANCHOR.equals(e.getMessage())) {
+ si.append(master.getString(R.string.mtm_trust_anchor));
+ } else
+ si.append(e.getLocalizedMessage());
+ si.append("\n");
+ }
+ si.append("\n");
+ si.append(master.getString(R.string.mtm_connect_anyway));
+ si.append("\n\n");
+ si.append(master.getString(R.string.mtm_cert_details));
+ for (X509Certificate c : chain) {
+ certDetails(si, c);
+ }
+ return si.toString();
+ }
+
+ private String hostNameMessage(X509Certificate cert, String hostname) {
+ StringBuffer si = new StringBuffer();
+
+ si.append(master.getString(R.string.mtm_hostname_mismatch, hostname));
+ si.append("\n\n");
+ try {
+ Collection<List<?>> sans = cert.getSubjectAlternativeNames();
+ if (sans == null) {
+ si.append(cert.getSubjectDN());
+ si.append("\n");
+ } else for (List<?> altName : sans) {
+ Object name = altName.get(1);
+ if (name instanceof String) {
+ si.append("[");
+ si.append((Integer)altName.get(0));
+ si.append("] ");
+ si.append(name);
+ si.append("\n");
+ }
+ }
+ } catch (CertificateParsingException e) {
+ e.printStackTrace();
+ si.append("<Parsing error: ");
+ si.append(e.getLocalizedMessage());
+ si.append(">\n");
+ }
+ si.append("\n");
+ si.append(master.getString(R.string.mtm_connect_anyway));
+ si.append("\n\n");
+ si.append(master.getString(R.string.mtm_cert_details));
+ certDetails(si, cert);
+ return si.toString();
+ }
+
+ // We can use Notification.Builder once MTM's minSDK is >= 11
+ @SuppressWarnings("deprecation")
+ void startActivityNotification(Intent intent, int decisionId, String certName) {
+ Notification n = new Notification(android.R.drawable.ic_lock_lock,
+ master.getString(R.string.mtm_notification),
+ System.currentTimeMillis());
+ PendingIntent call = PendingIntent.getActivity(master, 0, intent, 0);
+ n.setLatestEventInfo(master.getApplicationContext(),
+ master.getString(R.string.mtm_notification),
+ certName, call);
+ n.flags |= Notification.FLAG_AUTO_CANCEL;
+
+ notificationManager.notify(NOTIFICATION_ID + decisionId, n);
+ }
+
+ /**
+ * Returns the top-most entry of the activity stack.
+ *
+ * @return the Context of the currently bound UI or the master context if none is bound
+ */
+ Context getUI() {
+ return (foregroundAct != null) ? foregroundAct : master;
+ }
+
+ int interact(final String message, final int titleId) {
+ /* prepare the MTMDecision blocker object */
+ MTMDecision choice = new MTMDecision();
+ final int myId = createDecisionId(choice);
+
+ masterHandler.post(new Runnable() {
+ public void run() {
+ Intent ni = new Intent(master, MemorizingActivity.class);
+ ni.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
+ ni.putExtra(DECISION_INTENT_ID, myId);
+ ni.putExtra(DECISION_INTENT_CERT, message);
+ ni.putExtra(DECISION_TITLE_ID, titleId);
+
+ // we try to directly start the activity and fall back to
+ // making a notification
+ try {
+ getUI().startActivity(ni);
+ } catch (Exception e) {
+ LOGGER.log(Level.FINE, "startActivity(MemorizingActivity)", e);
+ startActivityNotification(ni, myId, message);
+ }
+ }
+ });
+
+ LOGGER.log(Level.FINE, "openDecisions: " + openDecisions + ", waiting on " + myId);
+ try {
+ synchronized(choice) { choice.wait(); }
+ } catch (InterruptedException e) {
+ LOGGER.log(Level.FINER, "InterruptedException", e);
+ }
+ LOGGER.log(Level.FINE, "finished wait on " + myId + ": " + choice.state);
+ return choice.state;
+ }
+
+ void interactCert(final X509Certificate[] chain, String authType, CertificateException cause)
+ throws CertificateException
+ {
+ switch (interact(certChainMessage(chain, cause), R.string.mtm_accept_cert)) {
+ case MTMDecision.DECISION_ALWAYS:
+ storeCert(chain[0]); // only store the server cert, not the whole chain
+ case MTMDecision.DECISION_ONCE:
+ break;
+ default:
+ throw (cause);
+ }
+ }
+
+ boolean interactHostname(X509Certificate cert, String hostname)
+ {
+ switch (interact(hostNameMessage(cert, hostname), R.string.mtm_accept_servername)) {
+ case MTMDecision.DECISION_ALWAYS:
+ storeCert(hostname, cert);
+ case MTMDecision.DECISION_ONCE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected static void interactResult(int decisionId, int choice) {
+ MTMDecision d;
+ synchronized(openDecisions) {
+ d = openDecisions.get(decisionId);
+ openDecisions.remove(decisionId);
+ }
+ if (d == null) {
+ LOGGER.log(Level.SEVERE, "interactResult: aborting due to stale decision reference!");
+ return;
+ }
+ synchronized(d) {
+ d.state = choice;
+ d.notify();
+ }
+ }
+
+ class MemorizingHostnameVerifier implements HostnameVerifier {
+ private HostnameVerifier defaultVerifier;
+
+ public MemorizingHostnameVerifier(HostnameVerifier wrapped) {
+ defaultVerifier = wrapped;
+ }
+
+ protected boolean verify(String hostname, SSLSession session, boolean interactive) {
+ LOGGER.log(Level.FINE, "hostname verifier for " + hostname + ", trying default verifier first");
+ // if the default verifier accepts the hostname, we are done
+ if (defaultVerifier.verify(hostname, session)) {
+ LOGGER.log(Level.FINE, "default verifier accepted " + hostname);
+ return true;
+ }
+ // otherwise, we check if the hostname is an alias for this cert in our keystore
+ try {
+ X509Certificate cert = (X509Certificate)session.getPeerCertificates()[0];
+ //Log.d(TAG, "cert: " + cert);
+ if (cert.equals(appKeyStore.getCertificate(hostname.toLowerCase(Locale.US)))) {
+ LOGGER.log(Level.FINE, "certificate for " + hostname + " is in our keystore. accepting.");
+ return true;
+ } else {
+ LOGGER.log(Level.FINE, "server " + hostname + " provided wrong certificate, asking user.");
+ if (interactive) {
+ return interactHostname(cert, hostname);
+ } else {
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return verify(hostname, session, true);
+ }
+ }
+
+ class NonInteractiveMemorizingHostnameVerifier extends MemorizingHostnameVerifier {
+
+ public NonInteractiveMemorizingHostnameVerifier(HostnameVerifier wrapped) {
+ super(wrapped);
+ }
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return verify(hostname, session, true);
+ }
+
+
+ }
+
+ public X509TrustManager getNonInteractive() {
+ return new NonInteractiveMemorizingTrustManager();
+ }
+
+ private class NonInteractiveMemorizingTrustManager implements X509TrustManager {
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ MemorizingTrustManager.this.checkCertTrusted(chain, authType, false, false);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ MemorizingTrustManager.this.checkCertTrusted(chain, authType, true, false);
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return MemorizingTrustManager.this.getAcceptedIssuers();
+ }
+
+ }
+}
D libs/android-support-v13.jar => libs/android-support-v13.jar +0 -0
D libs/bcprov-jdk15on-150.jar => libs/bcprov-jdk15on-150.jar +0 -0
D libs/minidns => libs/minidns +0 -1
@@ 1,1 0,0 @@
-Subproject commit 152be6eb1a22da8cebe24ac4ee05b487936c9f2a
A libs/minidns/.gitignore => libs/minidns/.gitignore +107 -0
@@ 0,0 1,107 @@
+# From https://github.com/github/gitignore
+
+# # # # # # # # # # # #
+# Android gitignore #
+# # # # # # # # # # # #
+
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+gradle.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# # # # # # # #
+# VIM / Linux #
+# # # # # # # #
+
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+*.un~
+Session.vim
+.netrwhist
+*~
+.directory
+
+# # # # # #
+# Eclipse #
+# # # # # #
+
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.classpath
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+# # # # #
+# OS X #
+# # # # #
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must ends with two \r.
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
A libs/minidns/LICENCE => libs/minidns/LICENCE +4 -0
@@ 0,0 1,4 @@
+This software may be used under the terms of (at your choice)
+- LGPL version 2 (or later) (see LICENCE_LGPL2.1 for details)
+- Apache Software licence (see LICENCE_APACHE for details)
+- WTFPL (see LICENCE_WTFPL for details)
A libs/minidns/LICENCE_APACHE => libs/minidns/LICENCE_APACHE +178 -0
@@ 0,0 1,178 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
A libs/minidns/LICENCE_LGPL2.1 => libs/minidns/LICENCE_LGPL2.1 +503 -0
@@ 0,0 1,503 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
A libs/minidns/LICENCE_WTFPL => libs/minidns/LICENCE_WTFPL +13 -0
@@ 0,0 1,13 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2014 Rene Treffer <treffer+wtfpl@measite.de>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
A libs/minidns/README.md => libs/minidns/README.md +8 -0
@@ 0,0 1,8 @@
+MiniDNS
+-------
+
+MiniDNS is a minimal dns client library for android. It can parse a basic set
+of resource records (A, AAAA, NS, SRV) and is easy to use and extend.
+
+This library is not intended to be used as a DNS server. You might want to
+look into dnsjava for such functionality.
A libs/minidns/build.gradle => libs/minidns/build.gradle +77 -0
@@ 0,0 1,77 @@
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'osgi'
+apply plugin: 'nexus'
+
+buildscript {
+ repositories {
+ jcenter()
+ mavenLocal()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'org.gradle.api.plugins:gradle-nexus-plugin:0.7.1'
+ }
+}
+
+group = 'de.measite.minidns'
+description = "A minimal DNS client library with support for A, AAAA, NS and SRV records"
+sourceCompatibility = 1.7
+version = 'git tag --points-at HEAD'.execute().text.trim()
+isSNAPSHOT = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim() == 'master'
+
+if (isSNAPSHOT) {
+ version = version + '-SNAPSHOT'
+}
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+nexus {
+ attachSources = true
+ attachTests = false
+ attachJavadoc = true
+ sign = true
+}
+
+modifyPom {
+ project {
+ name 'minidns'
+ description 'Minimal DNS library for java and android systems'
+ url 'https://github.com/rtreffer/minidns'
+ inceptionYear '2014'
+
+ scm {
+ url 'https://github.com/rtreffer/minidns'
+ connection 'scm:https://github.com/rtreffer/minidns'
+ developerConnection 'scm:git://github.com/rtreffer/minidns.git'
+ }
+
+ licenses {
+ license {
+ name 'The Apache Software License, Version 2.0'
+ url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ distribution 'repo'
+ }
+ }
+
+ developers {
+ developer {
+ id 'rtreffer'
+ name 'Rene Treffer'
+ email 'treffer@measite.de'
+ }
+ developer {
+ id 'flow'
+ name 'Florian Schmaus'
+ email 'flow@geekplace.eu'
+ }
+ }
+ }
+}
+
+dependencies {
+}<
\ No newline at end of file
A libs/minidns/gradle.properties.example => libs/minidns/gradle.properties.example +21 -0
@@ 0,0 1,21 @@
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+# GPG settings
+#
+
+# gpg key id
+#signing.keyId=DEADBEEF
+# the gpg key passphrase
+#signing.password=correcthorsebatterystaple
+# gpg keyring (this is the default gnupg keyring containing private keys)
+#signing.secretKeyRingFile=/home/ubuntu/.gnupg/secring.gpg
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+#
+# nexus settings
+#
+
+# the nexus username used for log in
+#nexusUsername=ubuntu
+# the nexus password
+#nexusPassword=correcthorsebatterystaple
A libs/minidns/src/main/java/de/measite/minidns/Client.java => libs/minidns/src/main/java/de/measite/minidns/Client.java +323 -0
@@ 0,0 1,323 @@
+package de.measite.minidns;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.lang.reflect.Method;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import de.measite.minidns.Record.CLASS;
+import de.measite.minidns.Record.TYPE;
+
+/**
+ * A minimal DNS client for SRV/A/AAAA/NS and CNAME lookups, with IDN support.
+ * This circumvents the missing javax.naming package on android.
+ */
+public class Client {
+
+ private static final Logger LOGGER = Logger.getLogger(Client.class.getName());
+
+ /**
+ * The internal random class for sequence generation.
+ */
+ protected Random random;
+
+ /**
+ * The buffer size for dns replies.
+ */
+ protected int bufferSize = 1500;
+
+ /**
+ * DNS timeout.
+ */
+ protected int timeout = 5000;
+
+ /**
+ * The internal DNS cache.
+ */
+ protected DNSCache cache;
+
+ /**
+ * Create a new DNS client with the given DNS cache.
+ * @param cache The backend DNS cache.
+ */
+ public Client(DNSCache cache) {
+ try {
+ random = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e1) {
+ random = new SecureRandom();
+ }
+ this.cache = cache;
+ }
+
+ /**
+ * Create a new DNS client.
+ */
+ public Client() {
+ this(null);
+ }
+
+ /**
+ * Query a nameserver for a single entry.
+ * @param name The DNS name to request.
+ * @param type The DNS type to request (SRV, A, AAAA, ...).
+ * @param clazz The class of the request (usually IN for Internet).
+ * @param host The DNS server host.
+ * @param port The DNS server port.
+ * @return The response (or null on timeout / failure).
+ * @throws IOException On IO Errors.
+ */
+ public DNSMessage query(String name, TYPE type, CLASS clazz, String host, int port)
+ throws IOException
+ {
+ Question q = new Question(name, type, clazz);
+ return query(q, host, port);
+ }
+
+ /**
+ * Query a nameserver for a single entry.
+ * @param name The DNS name to request.
+ * @param type The DNS type to request (SRV, A, AAAA, ...).
+ * @param clazz The class of the request (usually IN for Internet).
+ * @param host The DNS server host.
+ * @return The response (or null on timeout / failure).
+ * @throws IOException On IO Errors.
+ */
+ public DNSMessage query(String name, TYPE type, CLASS clazz, String host)
+ throws IOException
+ {
+ Question q = new Question(name, type, clazz);
+ return query(q, host);
+ }
+
+ /**
+ * Query the system nameserver for a single entry.
+ * @param name The DNS name to request.
+ * @param type The DNS type to request (SRV, A, AAAA, ...).
+ * @param clazz The class of the request (usually IN for Internet).
+ * @return The response (or null on timeout/error).
+ * @return The DNSMessage reply or null.
+ */
+ public DNSMessage query(String name, TYPE type, CLASS clazz)
+ {
+ Question q = new Question(name, type, clazz);
+ return query(q);
+ }
+
+ /**
+ * Query a specific server for one entry.
+ * @param q The question section of the DNS query.
+ * @param host The dns server host.
+ * @return The response (or null on timeout/error).
+ * @throws IOException On IOErrors.
+ */
+ public DNSMessage query(Question q, String host) throws IOException {
+ return query(q, host, 53);
+ }
+
+ /**
+ * Query a specific server for one entry.
+ * @param q The question section of the DNS query.
+ * @param host The dns server host.
+ * @param port the dns port.
+ * @return The response (or null on timeout/error).
+ * @throws IOException On IOErrors.
+ */
+ public DNSMessage query(Question q, String host, int port) throws IOException {
+ DNSMessage dnsMessage = (cache == null) ? null : cache.get(q);
+ if (dnsMessage != null) {
+ return dnsMessage;
+ }
+ DNSMessage message = new DNSMessage();
+ message.setQuestions(new Question[]{q});
+ message.setRecursionDesired(true);
+ message.setId(random.nextInt());
+ byte[] buf = message.toArray();
+ try (DatagramSocket socket = new DatagramSocket()) {
+ DatagramPacket packet = new DatagramPacket(buf, buf.length,
+ InetAddress.getByName(host), port);
+ socket.setSoTimeout(timeout);
+ socket.send(packet);
+ packet = new DatagramPacket(new byte[bufferSize], bufferSize);
+ socket.receive(packet);
+ dnsMessage = DNSMessage.parse(packet.getData());
+ if (dnsMessage.getId() != message.getId()) {
+ return null;
+ }
+ for (Record record : dnsMessage.getAnswers()) {
+ if (record.isAnswer(q)) {
+ if (cache != null) {
+ cache.put(q, dnsMessage);
+ }
+ break;
+ }
+ }
+ return dnsMessage;
+ }
+ }
+
+ /**
+ * Query the system DNS server for one entry.
+ * @param q The question section of the DNS query.
+ * @return The response (or null on timeout/error).
+ */
+ public DNSMessage query(Question q) {
+ // While this query method does in fact re-use query(Question, String)
+ // we still do a cache lookup here in order to avoid unnecessary
+ // findDNS()calls, which are expensive on Android. Note that we do not
+ // put the results back into the Cache, as this is already done by
+ // query(Question, String).
+ DNSMessage message = cache.get(q);
+ if (message != null) {
+ return message;
+ }
+ String dnsServer[] = findDNS();
+ for (String dns : dnsServer) {
+ try {
+ message = query(q, dns);
+ if (message == null) {
+ continue;
+ }
+ if (message.getResponseCode() !=
+ DNSMessage.RESPONSE_CODE.NO_ERROR) {
+ continue;
+ }
+ for (Record record: message.getAnswers()) {
+ if (record.isAnswer(q)) {
+ return message;
+ }
+ }
+ } catch (IOException ioe) {
+ LOGGER.log(Level.FINE, "IOException in query", ioe);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve a list of currently configured DNS servers.
+ * @return The server array.
+ */
+ public String[] findDNS() {
+ String[] result = findDNSByReflection();
+ if (result != null) {
+ LOGGER.fine("Got DNS servers via reflection: " + Arrays.toString(result));
+ return result;
+ }
+
+ result = findDNSByExec();
+ if (result != null) {
+ LOGGER.fine("Got DNS servers via exec: " + Arrays.toString(result));
+ return result;
+ }
+
+ // fallback for ipv4 and ipv6 connectivity
+ // see https://developers.google.com/speed/public-dns/docs/using
+ LOGGER.fine("No DNS found? Using fallback [8.8.8.8, [2001:4860:4860::8888]]");
+
+ return new String[]{"8.8.8.8", "[2001:4860:4860::8888]"};
+ }
+
+ /**
+ * Try to retrieve the list of dns server by executing getprop.
+ * @return Array of servers, or null on failure.
+ */
+ protected String[] findDNSByExec() {
+ try {
+ Process process = Runtime.getRuntime().exec("getprop");
+ InputStream inputStream = process.getInputStream();
+ LineNumberReader lnr = new LineNumberReader(
+ new InputStreamReader(inputStream));
+ String line = null;
+ HashSet<String> server = new HashSet<String>(6);
+ while ((line = lnr.readLine()) != null) {
+ int split = line.indexOf("]: [");
+ if (split == -1) {
+ continue;
+ }
+ String property = line.substring(1, split);
+ String value = line.substring(split + 4, line.length() - 1);
+ if (property.endsWith(".dns") || property.endsWith(".dns1") ||
+ property.endsWith(".dns2") || property.endsWith(".dns3") ||
+ property.endsWith(".dns4")) {
+
+ // normalize the address
+
+ InetAddress ip = InetAddress.getByName(value);
+
+ if (ip == null) continue;
+
+ value = ip.getHostAddress();
+
+ if (value == null) continue;
+ if (value.length() == 0) continue;
+
+ server.add(value);
+ }
+ }
+ if (server.size() > 0) {
+ return server.toArray(new String[server.size()]);
+ }
+ } catch (IOException e) {
+ LOGGER.log(Level.WARNING, "Exception in findDNSByExec", e);
+ }
+ return null;
+ }
+
+ /**
+ * Try to retrieve the list of dns server by calling SystemProperties.
+ * @return Array of servers, or null on failure.
+ */
+ protected String[] findDNSByReflection() {
+ try {
+ Class<?> SystemProperties =
+ Class.forName("android.os.SystemProperties");
+ Method method = SystemProperties.getMethod("get",
+ new Class[] { String.class });
+
+ ArrayList<String> servers = new ArrayList<String>(5);
+
+ for (String propKey : new String[] {
+ "net.dns1", "net.dns2", "net.dns3", "net.dns4"}) {
+
+ String value = (String)method.invoke(null, propKey);
+
+ if (value == null) continue;
+ if (value.length() == 0) continue;
+ if (servers.contains(value)) continue;
+
+ InetAddress ip = InetAddress.getByName(value);
+
+ if (ip == null) continue;
+
+ value = ip.getHostAddress();
+
+ if (value == null) continue;
+ if (value.length() == 0) continue;
+ if (servers.contains(value)) continue;
+
+ servers.add(value);
+ }
+
+ if (servers.size() > 0) {
+ return servers.toArray(new String[servers.size()]);
+ }
+ } catch (Exception e) {
+ // we might trigger some problems this way
+ LOGGER.log(Level.WARNING, "Exception in findDNSByReflection", e);
+ }
+ return null;
+ }
+
+}
A libs/minidns/src/main/java/de/measite/minidns/DNSCache.java => libs/minidns/src/main/java/de/measite/minidns/DNSCache.java +23 -0
@@ 0,0 1,23 @@
+package de.measite.minidns;
+
+/**
+ * Cache for DNS Entries. Implementations must be thread safe.
+ */
+public interface DNSCache {
+
+ /**
+ * Add an an dns answer/response for a given dns question. Implementations
+ * should honor the ttl / receive timestamp.
+ * @param q The question.
+ * @param message The dns message.
+ */
+ void put(Question q, DNSMessage message);
+
+ /**
+ * Request a cached dns response.
+ * @param q The dns question.
+ * @return The dns message.
+ */
+ DNSMessage get(Question q);
+
+}
A libs/minidns/src/main/java/de/measite/minidns/DNSMessage.java => libs/minidns/src/main/java/de/measite/minidns/DNSMessage.java +524 -0
@@ 0,0 1,524 @@
+package de.measite.minidns;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * A DNS message as defined by rfc1035. The message consists of a header and
+ * 4 sections: question, answer, nameserver and addition resource record
+ * section.
+ * A message can either be parsed ({@link DNSMessage#parse(byte[])}) or serialized
+ * ({@link DNSMessage#toArray()}).
+ */
+public class DNSMessage {
+
+ /**
+ * Possible DNS reply codes.
+ */
+ public static enum RESPONSE_CODE {
+ NO_ERROR(0), FORMAT_ERR(1), SERVER_FAIL(2), NX_DOMAIN(3),
+ NO_IMP(4), REFUSED(5), YXDOMAIN(6), YXRRSET(7),
+ NXRRSET(8), NOT_AUTH(9),NOT_ZONE(10);
+
+ /**
+ * Reverse lookup table for response codes.
+ */
+ private final static RESPONSE_CODE INVERSE_LUT[] = new RESPONSE_CODE[]{
+ NO_ERROR, FORMAT_ERR, SERVER_FAIL, NX_DOMAIN, NO_IMP,
+ REFUSED, YXDOMAIN, YXRRSET, NXRRSET, NOT_AUTH, NOT_ZONE,
+ null, null, null, null, null
+ };
+
+ /**
+ * The response code value.
+ */
+ private final byte value;
+
+ /**
+ * Create a new response code.
+ * @param value The response code value.
+ */
+ private RESPONSE_CODE(int value) {
+ this.value = (byte)value;
+ }
+
+ /**
+ * Retrieve the byte value of the response code.
+ * @return the response code.
+ */
+ public byte getValue() {
+ return (byte) value;
+ }
+
+ /**
+ * Retrieve the response code for a byte value.
+ * @param value The byte value.
+ * @return The symbolic response code or null.
+ * @throws IllegalArgumentException if the value is not in the range of
+ * 0..15.
+ */
+ public static RESPONSE_CODE getResponseCode(int value) {
+ if (value < 0 || value > 15) {
+ throw new IllegalArgumentException();
+ }
+ return INVERSE_LUT[value];
+ }
+
+ };
+
+ /**
+ * Symbolic DNS Opcode values.
+ */
+ public static enum OPCODE {
+ QUERY(0),
+ INVERSE_QUERY(1),
+ STATUS(2),
+ NOTIFY(4),
+ UPDATE(5);
+
+ /**