├── .gitignore ├── COPYING ├── README.md ├── WebSMSAPI ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── de │ │ └── ub0r │ │ └── android │ │ └── websms │ │ └── connector │ │ └── common │ │ ├── Base64Coder.java │ │ ├── BasicConnector.java │ │ ├── BasicSMSLengthCalculator.java │ │ ├── BuilderWrapper11.java │ │ ├── CharacterTable.java │ │ ├── CharacterTableSMSLengthCalculator.java │ │ ├── Connector.java │ │ ├── ConnectorCommand.java │ │ ├── ConnectorPreferenceActivity.java │ │ ├── ConnectorService.java │ │ ├── ConnectorSpec.java │ │ ├── FakeSocketFactory.java │ │ ├── FakeTrustManager.java │ │ ├── InfoActivity.java │ │ ├── KnownFingerprintTrustManager.java │ │ ├── Log.java │ │ ├── SMSLengthCalculator.java │ │ ├── Utils.java │ │ ├── WebSMSException.java │ │ ├── WebSMSNoNetworkException.java │ │ └── package-info.java │ └── res │ ├── drawable-hdpi-v11 │ └── stat_notify_sms_pending.png │ ├── drawable-hdpi-v9 │ └── stat_notify_sms_pending.png │ ├── drawable-hdpi │ ├── icon.png │ └── stat_notify_sms_pending.png │ ├── drawable-ldpi-v9 │ └── stat_notify_sms_pending.png │ ├── drawable-mdpi-v11 │ └── stat_notify_sms_pending.png │ ├── drawable-mdpi-v9 │ └── stat_notify_sms_pending.png │ ├── drawable-mdpi │ ├── icon.png │ └── stat_notify_sms_pending.png │ ├── drawable-xhdpi │ ├── icon.png │ └── stat_notify_sms_pending.png │ ├── drawable │ ├── icon.png │ └── stat_notify_sms_pending.png │ ├── values-cs │ └── strings.xml │ ├── values-de │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-hu │ └── strings.xml │ ├── values-it │ └── strings.xml │ ├── values-pt │ └── strings.xml │ ├── values-ro │ └── strings.xml │ ├── values-ru │ └── strings.xml │ ├── values-sk │ └── strings.xml │ ├── values-tr │ └── strings.xml │ └── values │ └── strings.xml ├── build.gradle ├── doc ├── DeveloperFAQ.md ├── DeveloperHelp.md └── sequence.png ├── hi-res ├── promo.png ├── promo.xcf ├── websms-connector-icon-512x512.png ├── websms-connector-icon-512x512_white.png └── websms-connector-icon.svgz └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | gen 3 | .ant-targets-build.xml 4 | local.properties 5 | build.properties 6 | *.zip 7 | *.jar 8 | *.swp 9 | .gradle 10 | /local.properties 11 | /.idea/workspace.xml 12 | .DS_Store 13 | build 14 | *.iml 15 | gradle 16 | gradlew 17 | .idea 18 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discontinued 2 | 3 | This app is discontinued and removed from all distribution channels. 4 | 5 | # General 6 | 7 | This is the API to build connectors for [websms][1]. 8 | Please see one of the open source connectors to get an idea how to use the API. 9 | A very good example fot the use of BasicConnector with a very straight forward API is [cherry-sms][2]. 10 | Check out the [o2 connector][3] to get an idea of a connector implementing the base class Connector and parsing a full website. 11 | 12 | ## How to build 13 | 14 | There are two ways to build a connector with this websms-api. 15 | 16 | ### Android-Studio / gradle / maven 17 | 18 | Add the websms-api maven repository to your build.gradle and simply reference the remote dependency. 19 | There is no need to check out/ clone the api manually. 20 | 21 | repositories { 22 | maven { 23 | url 'https://raw.githubusercontent.com/felixb/mvn-repo/master/' 24 | } 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | compile 'de.ub0r.android.websms.connector.common:WebSMSAPI:1.1' 30 | } 31 | 32 | You can see it in full details in the [cherry-sms connector's code base][2]. 33 | In maven just in add the dependency like this. 34 | 35 | 36 | de.ub0r.android.websms.connector.common 37 | WebSMSAPI 38 | {latest.version} 39 | jar 40 | 41 | 42 | ### Eclipse / ant 43 | 44 | Please clone this git repo and check out the tag `build-env-eclipse`. 45 | You'll need to import this eclipse project and reference it as library project in your connector. 46 | 47 | ## Further reading 48 | 49 | * [Developer Help][4] 50 | * [Developer FAQ][5] 51 | 52 | [1]: http://github.com/felixb/websms/ 53 | [2]: https://github.com/felixb/websms-connector-cherrysms/ 54 | [3]: https://github.com/lmb/websms-connector-o2/ 55 | [4]: https://github.com/felixb/websms-api/blob/master/doc/DeveloperHelp.md 56 | [5]: https://github.com/felixb/websms-api/blob/master/doc/DeveloperFAQ.md 57 | -------------------------------------------------------------------------------- /WebSMSAPI/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /WebSMSAPI/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:1.0.1' 7 | } 8 | } 9 | apply plugin: 'com.android.library' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | android { 16 | compileSdkVersion 19 17 | buildToolsVersion '21.1.2' 18 | 19 | defaultConfig { 20 | minSdkVersion 5 21 | targetSdkVersion 19 22 | } 23 | } 24 | 25 | apply plugin: 'maven' 26 | apply plugin: 'signing' 27 | 28 | configurations { 29 | archives { 30 | extendsFrom configurations.default 31 | } 32 | } 33 | 34 | signing { 35 | required { has("release") && gradle.taskGraph.hasTask("uploadArchives") } 36 | sign configurations.archives 37 | } 38 | 39 | afterEvaluate { project -> 40 | 41 | uploadArchives { 42 | def user = null 43 | def repo = null 44 | 'git remote -v'.execute(null, project.projectDir).getText().find('.*?git@github.com[:/](.*?)/(.*?)(.git)? .*?') { 45 | match -> 46 | user = match[1] 47 | repo = match[2] 48 | } 49 | 50 | def githubUrl = 'https://api.github.com/repos/' + user + '/' + repo; 51 | if (System.getenv().GITHUB_TOKEN) { 52 | githubUrl += '?access_token=' + System.getenv().GITHUB_TOKEN 53 | } 54 | def repoInfo = new groovy.json.JsonSlurper().parseText(new URL(githubUrl).getText()) 55 | 56 | def android_manifest = new XmlParser(false, false). 57 | parseText(new File(project.projectDir, 'src/main/AndroidManifest.xml').getText()) 58 | def versionName = android_manifest.'@android:versionName' 59 | def package_name = android_manifest.'@package' 60 | def artifact_id = repo.toLowerCase() 61 | project.version = versionName 62 | project.group = package_name 63 | 64 | configuration = configurations.archives 65 | repositories.mavenDeployer { 66 | // beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 67 | 68 | repository(url: "file:///tmp/websms-api/") 69 | 70 | pom.project { 71 | name repo 72 | packaging 'jar' 73 | description repoInfo.description 74 | url repoInfo.html_url 75 | 76 | scm { 77 | url repoInfo.git_url 78 | connection repoInfo.git_url 79 | developerConnection repoInfo.ssh_url 80 | } 81 | 82 | licenses { 83 | license { 84 | name 'The Apache Software License, Version 2.0' 85 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 86 | distribution 'repo' 87 | } 88 | } 89 | 90 | developers { 91 | developer { 92 | id user 93 | name 'Felix Bechstein' 94 | email 'f@ub0r.de' 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/Base64Coder.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | /** 4 | * A Base64 Encoder/Decoder. 5 | *

6 | * This class is used to encode and decode data in Base64 format as described in RFC 1521. 7 | *

8 | * This is "Open Source" software and released under the GNU/LGPL license.
10 | * It is provided "as is" without warranty of any kind.
11 | * Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland.
12 | * Home page: www.source-code.biz
13 | *

14 | * Version history:
15 | * 2003-07-22 Christian d'Heureuse (chdh): Module created.
16 | * 2005-08-11 chdh: Lincense changed from GPL to LGPL.
17 | * 2006-11-21 chdh:
18 | *   Method encode(String) renamed to encodeString(String).
19 | *   Method decode(String) renamed to decodeString(String).
20 | *   New method encode(byte[],int) added.
21 | *   New method decode(String) added.
22 | */ 23 | public final class Base64Coder { 24 | 25 | /** Mapping table from 6-bit nibbles to Base64 characters. */ 26 | private static char[] map1 = new char[64]; 27 | static { 28 | int i = 0; 29 | for (char c = 'A'; c <= 'Z'; c++) { 30 | map1[i++] = c; 31 | } 32 | for (char c = 'a'; c <= 'z'; c++) { 33 | map1[i++] = c; 34 | } 35 | for (char c = '0'; c <= '9'; c++) { 36 | map1[i++] = c; 37 | } 38 | map1[i++] = '+'; 39 | map1[i++] = '/'; 40 | } 41 | 42 | /** Mapping table from Base64 characters to 6-bit nibbles. */ 43 | private static byte[] map2 = new byte[128]; 44 | static { 45 | for (int i = 0; i < map2.length; i++) { 46 | map2[i] = -1; 47 | } 48 | for (int i = 0; i < 64; i++) { 49 | map2[map1[i]] = (byte) i; 50 | } 51 | } 52 | 53 | /** 54 | * Encodes a string into Base64 format. No blanks or line breaks are inserted. 55 | * 56 | * @param s 57 | * a String to be encoded. 58 | * @return A String with the Base64 encoded data. 59 | */ 60 | public static String encodeString(final String s) { 61 | return new String(encode(s.getBytes())); 62 | } 63 | 64 | /** 65 | * Encodes a byte array into Base64 format. No blanks or line breaks are inserted. 66 | * 67 | * @param in 68 | * an array containing the data bytes to be encoded. 69 | * @return A character array with the Base64 encoded data. 70 | */ 71 | public static char[] encode(final byte[] in) { 72 | return encode(in, in.length); 73 | } 74 | 75 | /** 76 | * Encodes a byte array into Base64 format. No blanks or line breaks are inserted. 77 | * 78 | * @param in 79 | * an array containing the data bytes to be encoded. 80 | * @param iLen 81 | * number of bytes to process in in. 82 | * @return A character array with the Base64 encoded data. 83 | */ 84 | public static char[] encode(final byte[] in, final int iLen) { 85 | int oDataLen = (iLen * 4 + 2) / 3; // output length without padding 86 | int oLen = ((iLen + 2) / 3) * 4; // output length including padding 87 | char[] out = new char[oLen]; 88 | int ip = 0; 89 | int op = 0; 90 | while (ip < iLen) { 91 | int i0 = in[ip++] & 0xff; 92 | int i1 = ip < iLen ? in[ip++] & 0xff : 0; 93 | int i2 = ip < iLen ? in[ip++] & 0xff : 0; 94 | int o0 = i0 >>> 2; 95 | int o1 = ((i0 & 3) << 4) | (i1 >>> 4); 96 | int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); 97 | int o3 = i2 & 0x3F; 98 | out[op++] = map1[o0]; 99 | out[op++] = map1[o1]; 100 | out[op] = op < oDataLen ? map1[o2] : '='; 101 | op++; 102 | out[op] = op < oDataLen ? map1[o3] : '='; 103 | op++; 104 | } 105 | return out; 106 | } 107 | 108 | /** 109 | * Decodes a string from Base64 format. 110 | * 111 | * @param s 112 | * a Base64 String to be decoded. 113 | * @return A String containing the decoded data. 114 | */ 115 | public static String decodeString(final String s) { 116 | return new String(decode(s)); 117 | } 118 | 119 | /** 120 | * Decodes a byte array from Base64 format. 121 | * 122 | * @param s 123 | * a Base64 String to be decoded. 124 | * @return An array containing the decoded data bytes. 125 | */ 126 | public static byte[] decode(final String s) { 127 | return decode(s.toCharArray()); 128 | } 129 | 130 | /** 131 | * Decodes a byte array from Base64 format. No blanks or line breaks are allowed within the 132 | * Base64 encoded data. 133 | * 134 | * @param in 135 | * a character array containing the Base64 encoded data. 136 | * @return An array containing the decoded data bytes. 137 | */ 138 | public static byte[] decode(final char[] in) { 139 | int iLen = in.length; 140 | if (iLen % 4 != 0) { 141 | throw new IllegalArgumentException( 142 | "Length of Base64 encoded input string is not a multiple of 4."); 143 | } 144 | while (iLen > 0 && in[iLen - 1] == '=') { 145 | iLen--; 146 | } 147 | int oLen = (iLen * 3) / 4; 148 | byte[] out = new byte[oLen]; 149 | int ip = 0; 150 | int op = 0; 151 | while (ip < iLen) { 152 | int i0 = in[ip++]; 153 | int i1 = in[ip++]; 154 | int i2 = ip < iLen ? in[ip++] : 'A'; 155 | int i3 = ip < iLen ? in[ip++] : 'A'; 156 | if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { 157 | throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 158 | } 159 | int b0 = map2[i0]; 160 | int b1 = map2[i1]; 161 | int b2 = map2[i2]; 162 | int b3 = map2[i3]; 163 | if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { 164 | throw new IllegalArgumentException("Illegal character in Base64 encoded data."); 165 | } 166 | int o0 = (b0 << 2) | (b1 >>> 4); 167 | int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); 168 | int o2 = ((b2 & 3) << 6) | b3; 169 | out[op++] = (byte) o0; 170 | if (op < oLen) { 171 | out[op++] = (byte) o1; 172 | } 173 | if (op < oLen) { 174 | out[op++] = (byte) o2; 175 | } 176 | } 177 | return out; 178 | } 179 | 180 | /** 181 | * Dummy constructor. 182 | */ 183 | private Base64Coder() { 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/BasicConnector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.io.IOException; 22 | import java.net.HttpURLConnection; 23 | import java.util.ArrayList; 24 | 25 | import org.apache.http.Header; 26 | import org.apache.http.HttpEntity; 27 | import org.apache.http.HttpResponse; 28 | import org.apache.http.message.BasicNameValuePair; 29 | 30 | import android.content.Context; 31 | import android.content.Intent; 32 | import android.text.TextUtils; 33 | import de.ub0r.android.websms.connector.common.Utils.HttpOptions; 34 | 35 | /** 36 | * AsyncTask to manage IO to a basic WebAPI. 37 | * 38 | * @author flx 39 | */ 40 | public abstract class BasicConnector extends Connector { 41 | /** Tag for output. */ 42 | private static final String TAG = "bcon"; 43 | /** User Agent. */ 44 | private static final String USERAGENT = // . 45 | "curl/7.21.3 (x86_64-pc-linux-gnu) " 46 | + "libcurl/7.21.3 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18"; 47 | 48 | /** 49 | * Get the URL used for sending messages. 50 | * 51 | * @param context 52 | * {@link Context} 53 | * @param d 54 | * {@link ArrayList} of arguments 55 | * @return gateway URL for sending 56 | */ 57 | protected String getUrlSend(final Context context, 58 | final ArrayList d) { 59 | return this.getUrlSend(d); 60 | } 61 | 62 | /** 63 | * Get the URL used for sending messages. 64 | * 65 | * @param d 66 | * {@link ArrayList} of arguments 67 | * @return gateway URL for sending 68 | */ 69 | @Deprecated 70 | protected String getUrlSend(final ArrayList d) { 71 | return null; 72 | } 73 | 74 | /** 75 | * Get the URL used for getting balance. 76 | * 77 | * @param context 78 | * {@link Context} 79 | * @param d 80 | * {@link ArrayList} of arguments 81 | * @return gateway URL for balance update 82 | */ 83 | protected String getUrlBalance(final Context context, 84 | final ArrayList d) { 85 | return this.getUrlBalance(d); 86 | } 87 | 88 | /** 89 | * Get the URL used for getting balance. 90 | * 91 | * @param d 92 | * {@link ArrayList} of arguments 93 | * @return gateway URL for balance update 94 | */ 95 | @Deprecated 96 | protected String getUrlBalance(final ArrayList d) { 97 | return null; 98 | } 99 | 100 | /** 101 | * Get HTTP method used for transmitting data to the Service. 102 | * 103 | * @return true to use POST, false for GET; default implementation returns 104 | * true 105 | */ 106 | protected boolean usePost(final ConnectorCommand command) { 107 | return true; 108 | } 109 | 110 | /** 111 | * Do HTTP basic auth. 112 | * 113 | * @return true to do HTTP basic auth 114 | */ 115 | protected boolean useBasicAuth() { 116 | return false; 117 | } 118 | 119 | /** @return user agent */ 120 | protected String getUserAgent() { 121 | return USERAGENT; 122 | } 123 | 124 | /** 125 | * Trust any SSL certificates. 126 | * 127 | * @return true to trust any SSL certificate, default implementation returns 128 | * false 129 | */ 130 | protected boolean trustAllSLLCerts() { 131 | return false; 132 | } 133 | 134 | /** 135 | * Array of SHA-1 fingerprint hashes of trusted SSL certificates. Only this 136 | * certificates will be accepted as trusted. 137 | * 138 | * @return array of trusted SSL certificates 139 | */ 140 | protected String[] trustedSSLCerts() { 141 | return null; 142 | } 143 | 144 | /** 145 | * Set encoding used for HTTP GET requests. 146 | * 147 | * @return encoding used for HTTP GET requests; default implementation uses 148 | * ISO-8859-15 149 | */ 150 | protected String getEncoding() { 151 | return "ISO-8859-15"; 152 | } 153 | 154 | /** 155 | * Set timeout for establishing a connection and waiting for a response from 156 | * the server. 157 | * 158 | * @return timeout; defaults to no timeout 159 | */ 160 | protected int getTimeout() { 161 | return 0; 162 | } 163 | 164 | /** 165 | * Set maximum number of HTTP connections. 166 | * 167 | * @param context 168 | * {@link Context} 169 | * @param cs 170 | * {@link ConnectorSpec} 171 | * @return number of connections; defaults to system default 172 | */ 173 | protected int getMaxHttpConnections(final Context context, 174 | final ConnectorSpec cs) { 175 | return 0; 176 | } 177 | 178 | /** 179 | * Set parameter name for username. 180 | * 181 | * @return API param for username 182 | */ 183 | protected abstract String getParamUsername(); 184 | 185 | /** 186 | * Set parameter name for password. 187 | * 188 | * @return API param for password 189 | */ 190 | protected abstract String getParamPassword(); 191 | 192 | /** 193 | * Set parameter name for recipients. 194 | * 195 | * @return API param for recipients 196 | */ 197 | protected abstract String getParamRecipients(); 198 | 199 | /** 200 | * Set paramteter name for text. 201 | * 202 | * @return API param for text 203 | */ 204 | protected abstract String getParamText(); 205 | 206 | /** 207 | * Set paramter name for sender id. 208 | * 209 | * @return API param for sender 210 | */ 211 | protected abstract String getParamSender(); 212 | 213 | /** 214 | * Set parameter name for send later. 215 | * 216 | * @return API param for send later; default implementation returns null 217 | */ 218 | protected String getParamSendLater() { 219 | return null; 220 | } 221 | 222 | /** 223 | * Set paramter name for selecting the sub connector. 224 | * 225 | * @return API param name for subconnector; default implementation returns 226 | * null 227 | */ 228 | protected String getParamSubconnector() { 229 | return null; 230 | } 231 | 232 | /** 233 | * Set paramter name for sending message as flash sms. 234 | * 235 | * @return API param for flash type; default implementation returns null 236 | */ 237 | protected String getParamFlash() { 238 | return null; 239 | } 240 | 241 | /** 242 | * Set username value. 243 | * 244 | * @param context 245 | * {@link Context} 246 | * @param command 247 | * {@link ConnectorCommand} 248 | * @param cs 249 | * {@link ConnectorSpec} 250 | * @return the username for authorization at the WebAPI. 251 | */ 252 | protected abstract String getUsername(final Context context, 253 | final ConnectorCommand command, final ConnectorSpec cs); 254 | 255 | /** 256 | * Set password value. 257 | * 258 | * @param context 259 | * {@link Context} 260 | * @param command 261 | * {@link ConnectorCommand} 262 | * @param cs 263 | * {@link ConnectorSpec} 264 | * @return the password for authorization at the WebAPI. 265 | */ 266 | protected abstract String getPassword(final Context context, 267 | final ConnectorCommand command, final ConnectorSpec cs); 268 | 269 | /** 270 | * Set selected sub connector. Get used subconnector. Default implementation 271 | * returns just the param subcon. 272 | * 273 | * @param subcon 274 | * id of selected subconnector 275 | * @return value for subconnector 276 | */ 277 | protected String getSubconnector(final String subcon) { 278 | return subcon; 279 | } 280 | 281 | /** 282 | * Set message's text. Default implementation returns just the given text. 283 | * 284 | * @param text 285 | * message body 286 | * @return value for text 287 | */ 288 | protected String getText(final String text) { 289 | return text; 290 | } 291 | 292 | /** 293 | * Set sender id value. 294 | * 295 | * @param context 296 | * {@link Context} 297 | * @param command 298 | * {@link ConnectorCommand} 299 | * @param cs 300 | * {@link ConnectorSpec} 301 | * @return value for sender. 302 | */ 303 | protected abstract String getSender(final Context context, 304 | final ConnectorCommand command, final ConnectorSpec cs); 305 | 306 | /** 307 | * Set recipients value. 308 | * 309 | * @param command 310 | * {@link ConnectorCommand} 311 | * @return value for recipients. 312 | */ 313 | protected abstract String getRecipients(final ConnectorCommand command); 314 | 315 | /** 316 | * Set send later value. Default implementation just returns the plain 317 | * value. 318 | * 319 | * @param sendLater 320 | * send later 321 | * @return value for send later 322 | */ 323 | protected String getSendLater(final long sendLater) { 324 | return String.valueOf(sendLater); 325 | } 326 | 327 | /** 328 | * Parse response. Implement this message to parse the returned text from 329 | * HTTP server. 330 | * 331 | * @param context 332 | * {@link Context} 333 | * @param command 334 | * {@link ConnectorCommand} 335 | * @param cs 336 | * {@link ConnectorSpec} 337 | * @param htmlText 338 | * HTTP response body 339 | */ 340 | protected abstract void parseResponse(final Context context, 341 | final ConnectorCommand command, final ConnectorSpec cs, 342 | final String htmlText); 343 | 344 | /** 345 | * Parse HTTP response code. Default implementation throws 346 | * {@link WebSMSException} if response != HTTP_OK. 347 | * 348 | * @param context 349 | * {@link Context} 350 | * @param response 351 | * {@link HttpResponse} 352 | */ 353 | protected void parseResponseCode(final Context context, 354 | final HttpResponse response) { 355 | final int resp = response.getStatusLine().getStatusCode(); 356 | if (resp != HttpURLConnection.HTTP_OK) { 357 | Log.e(TAG, "HTTP Status Line: " 358 | + response.getStatusLine().toString()); 359 | Log.e(TAG, "HTTP Headers:"); 360 | for (Header h : response.getAllHeaders()) { 361 | Log.e(TAG, h.getName() + ": " + h.getValue()); 362 | } 363 | try { 364 | final String htmlText = Utils.stream2str( 365 | response.getEntity().getContent()).trim(); 366 | Log.e(TAG, "HTTP Body:"); 367 | for (String l : htmlText.split("\n")) { 368 | Log.e(TAG, l); 369 | } 370 | } catch (Exception e) { 371 | Log.w(TAG, "error getting content", e); 372 | } 373 | throw new WebSMSException(context, R.string.error_http, 374 | String.valueOf(resp)); 375 | } 376 | } 377 | 378 | /** 379 | * Add some {@link BasicNameValuePair}s to arguments before calling the web 380 | * service. 381 | * 382 | * @param context 383 | * {@link Context} 384 | * @param command 385 | * {@link ConnectorCommand} 386 | * @param cs 387 | * {@link ConnectorSpec} 388 | * @param d 389 | * {@link ArrayList} of arguments 390 | */ 391 | protected void addExtraArgs(final Context context, 392 | final ConnectorCommand command, final ConnectorSpec cs, 393 | final ArrayList d) { 394 | // default implementation does nothing 395 | } 396 | 397 | /** 398 | * Add a HTTP entity and push it with HTTP POST. 399 | * 400 | * @param context 401 | * {@link Context} 402 | * @param command 403 | * {@link ConnectorCommand} 404 | * @param cs 405 | * {@link ConnectorSpec} 406 | * @return {@link HttpEntity} 407 | */ 408 | protected HttpEntity addHttpEntity(final Context context, 409 | final ConnectorCommand command, final ConnectorSpec cs) { 410 | return null; 411 | } 412 | 413 | /** 414 | * Send data. This method actually calls the web service with all set 415 | * parameters. The response is parsed in custom methods implemented by the 416 | * actual connector. 417 | * 418 | * @param context 419 | * Context 420 | * @param command 421 | * ConnectorCommand 422 | * @throws IOException 423 | * IOException 424 | */ 425 | private void sendData(final Context context, final ConnectorCommand command) 426 | throws IOException { 427 | // check network availability 428 | if (!Utils.isNetworkAvailable(context)) { 429 | throw new WebSMSNoNetworkException(context); 430 | } 431 | HttpOptions o = new HttpOptions(this.getEncoding()); 432 | o.userAgent = this.getUserAgent(); 433 | // get Connection 434 | final ConnectorSpec cs = this.getSpec(context); 435 | ArrayList d = new ArrayList(); 436 | final String text = command.getText(); 437 | if (text != null && text.length() > 0) { 438 | o.url = this.getUrlSend(context, d); 439 | final String subCon = command.getSelectedSubConnector(); 440 | addParam(d, this.getParamText(), this.getText(text)); 441 | addParam(d, this.getParamRecipients(), this.getRecipients(command)); 442 | 443 | if (command.getFlashSMS()) { 444 | addParam(d, this.getParamSubconnector(), this.getParamFlash()); 445 | } else { 446 | addParam(d, this.getParamSubconnector(), 447 | this.getSubconnector(subCon)); 448 | } 449 | 450 | final String customSender = command.getCustomSender(); 451 | if (customSender == null) { 452 | addParam(d, this.getParamSender(), 453 | this.getSender(context, command, cs)); 454 | } else { 455 | addParam(d, this.getParamSender(), customSender); 456 | } 457 | final long sendLater = command.getSendLater(); 458 | final String pSendLater = this.getParamSendLater(); 459 | if (sendLater > 0 && pSendLater != null) { 460 | d.add(new BasicNameValuePair(pSendLater, this 461 | .getSendLater(sendLater))); 462 | } 463 | } else { 464 | o.url = this.getUrlBalance(context, d); 465 | } 466 | 467 | if (!this.useBasicAuth()) { 468 | addParam(d, this.getParamUsername(), 469 | this.getUsername(context, command, cs)); 470 | addParam(d, this.getParamPassword(), 471 | this.getPassword(context, command, cs)); 472 | } 473 | 474 | this.addExtraArgs(context, command, cs, d); 475 | 476 | final String encoding = this.getEncoding(); 477 | if (!this.usePost(command)) { 478 | o.url = Utils.httpGetParams(o.url, d, encoding); 479 | d = null; 480 | } else { 481 | o.postData = this.addHttpEntity(context, command, cs); 482 | if (o.postData == null) { 483 | o.addFormParameter(d); 484 | } else { 485 | o.url = Utils.httpGetParams(o.url, d, encoding); 486 | d = null; 487 | } 488 | } 489 | if (this.useBasicAuth()) { 490 | o.addBasicAuthHeader(this.getUsername(context, command, cs), 491 | this.getPassword(context, command, cs)); 492 | } 493 | 494 | o.trustAll = this.trustAllSLLCerts(); 495 | o.knownFingerprints = this.trustedSSLCerts(); 496 | 497 | o.timeout = this.getTimeout(); 498 | o.maxConnections = this.getMaxHttpConnections(context, cs); 499 | 500 | Log.d(TAG, "HTTP REQUEST: " + o.url); 501 | HttpResponse response = Utils.getHttpClient(o); 502 | 503 | this.parseResponseCode(context, response); 504 | final String htmlText = Utils.stream2str( 505 | response.getEntity().getContent()).trim(); 506 | Log.d(TAG, "HTTP RESPONSE: " + htmlText); 507 | this.parseResponse(context, command, cs, htmlText); 508 | } 509 | 510 | /** 511 | * {@inheritDoc} 512 | */ 513 | @Override 514 | protected void doUpdate(final Context context, final Intent intent) 515 | throws IOException { 516 | this.sendData(context, new ConnectorCommand(intent)); 517 | } 518 | 519 | /** 520 | * {@inheritDoc} 521 | */ 522 | @Override 523 | protected void doSend(final Context context, final Intent intent) 524 | throws IOException { 525 | this.sendData(context, new ConnectorCommand(intent)); 526 | } 527 | 528 | /** 529 | * Add a {@link BasicNameValuePair} to a {@link ArrayList}. 530 | * 531 | * @param d 532 | * {@link ArrayList} of {@link BasicNameValuePair} 533 | * @param n 534 | * name 535 | * @param v 536 | * value 537 | * @return the list 538 | */ 539 | protected static ArrayList addParam( 540 | final ArrayList d, final String n, 541 | final String v) { 542 | if (!TextUtils.isEmpty(n)) { 543 | d.add(new BasicNameValuePair(n, v)); 544 | } 545 | return d; 546 | } 547 | } 548 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/BasicSMSLengthCalculator.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * A simple implementation of an SMSLengthCalculator. Provide an array of 8 | * message lengths representing the number of characters that can be added each 9 | * time before an additional SMS will be used. 10 | * 11 | * For example: [160, 149] - here the first 160 characters is just one SMS, the 12 | * next 149 (for a total of 309) would constitute 2 messages. 13 | * 14 | * Note that the final value implicitly repeats, so the above example is 15 | * actually [160, 149, 149, ...]. 16 | * 17 | * If the provider has a maximum message length and this is set correctly the 18 | * repeating message length will not be an issue. 19 | * 20 | * @author Fintan Fairmichael 21 | * 22 | */ 23 | public class BasicSMSLengthCalculator implements SMSLengthCalculator { 24 | private static final long serialVersionUID = -2841752540084364776L; 25 | 26 | private final int[] messageLengths; 27 | 28 | /** 29 | * 30 | * @param messageLengths 31 | * the message lengths representing the number of characters that 32 | * can be added at each point before an additional message is 33 | * required 34 | */ 35 | public BasicSMSLengthCalculator(final int[] messageLengths) { 36 | this.messageLengths = messageLengths; 37 | } 38 | 39 | private final int messageLength(final int index) { 40 | if (index >= this.messageLengths.length) { 41 | return this.messageLengths[this.messageLengths.length - 1]; 42 | } else { 43 | // Last message length repeats, if necessary 44 | return this.messageLengths[index]; 45 | } 46 | } 47 | 48 | @Override 49 | public int[] calculateLength(final String messageBody, 50 | final boolean use7bitOnly) { 51 | // Currently ignoring use7bitOnly param 52 | final int length = messageBody.length(); 53 | 54 | int numberSMSRequired = 0; 55 | int charsRemaining = length; 56 | int remainingTilNextSMS = 0; 57 | 58 | while (true) { 59 | final int messageLength = this.messageLength(numberSMSRequired); 60 | numberSMSRequired++; 61 | if (messageLength >= charsRemaining) { 62 | remainingTilNextSMS = messageLength - charsRemaining; 63 | break; 64 | } 65 | charsRemaining -= messageLength; 66 | } 67 | return new int[] { numberSMSRequired, length, remainingTilNextSMS, 0 }; 68 | } 69 | 70 | // Parcel stuff 71 | private BasicSMSLengthCalculator(final Parcel parcel) { 72 | this(parcel.createIntArray()); 73 | } 74 | 75 | public int describeContents() { 76 | return 0; 77 | } 78 | 79 | public void writeToParcel(final Parcel out, final int flags) { 80 | out.writeIntArray(this.messageLengths); 81 | } 82 | 83 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 84 | public BasicSMSLengthCalculator createFromParcel(final Parcel in) { 85 | return new BasicSMSLengthCalculator(in); 86 | } 87 | 88 | public BasicSMSLengthCalculator[] newArray(final int size) { 89 | return new BasicSMSLengthCalculator[size]; 90 | } 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/BuilderWrapper11.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import android.app.AlertDialog.Builder; 4 | import android.content.Context; 5 | 6 | /** 7 | * Get a {@link Builder} with theme support. 8 | * 9 | * @author flx 10 | */ 11 | final class BuilderWrapper11 { 12 | /** 13 | * Hide constructor. 14 | */ 15 | private BuilderWrapper11() { 16 | // nothing to do 17 | } 18 | 19 | /** 20 | * Get a {@link Builder}. 21 | * 22 | * @param context 23 | * {@link Context} 24 | * @param theme 25 | * theme 26 | * @return {@link Builder} 27 | */ 28 | static Builder getBuilder(final Context context, final int theme) { 29 | return new Builder(context, theme); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/CharacterTable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009-2012 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | import android.os.Bundle; 25 | 26 | /** 27 | * Character table is replacing unwanted characters with well behaving ones. 28 | * 29 | * @author Thomas Pilarski , Felix Bechstein 30 | * 31 | */ 32 | public final class CharacterTable { 33 | 34 | /** Mapping. */ 35 | private final Map mMap; 36 | 37 | /** 38 | * Default constructor. 39 | * 40 | * @param map 41 | * {@link Map} holding bad and good characters 42 | */ 43 | public CharacterTable(final Map map) { 44 | // this.mMap = new HashMap(map.size()); 45 | // this.mMap.putAll(map); 46 | this.mMap = map; 47 | } 48 | 49 | /** 50 | * Import from {@link Bundle} constructor. 51 | * 52 | * @param b 53 | * {@link Bundle} holding bad and good characters 54 | */ 55 | public CharacterTable(final Bundle b) { 56 | this.mMap = new HashMap(b.size()); 57 | for (String k : b.keySet()) { 58 | this.mMap.put(k, b.getString(k)); 59 | } 60 | } 61 | 62 | /** 63 | * Encode {@link String}. 64 | * 65 | * @param str 66 | * {@link String} 67 | * @return encoded {@link String} 68 | */ 69 | public String encodeString(final String str) { 70 | final int l = str.length(); 71 | final StringBuffer strb = new StringBuffer(l); 72 | for (int i = 0; i < l; i++) { 73 | String s = str.substring(i, i + 1); 74 | String chr = this.mMap.get(s); 75 | if (chr == null) { 76 | strb.append(s); 77 | } else { 78 | strb.append(chr); 79 | } 80 | } 81 | return strb.toString(); 82 | } 83 | 84 | /** 85 | * @return inner {@link Map} 86 | */ 87 | public Map getMap() { 88 | return this.mMap; 89 | } 90 | 91 | /** 92 | * @return inner {@link Map} as {@link Bundle} 93 | */ 94 | public Bundle getBundle() { 95 | final Bundle b = new Bundle(this.mMap.size()); 96 | for (String k : this.mMap.keySet()) { 97 | b.putString(k, this.mMap.get(k)); 98 | } 99 | return b; 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/CharacterTableSMSLengthCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009-2012 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import android.os.Bundle; 22 | import android.os.Parcel; 23 | import android.os.Parcelable; 24 | import android.telephony.SmsMessage; 25 | 26 | /** 27 | * This implementation of an SMSLengthCalculator replaces bad characters with a 28 | * {@link CharacterTable} before calculating the message length. This class does 29 | * need at least an Android API 4. 30 | * 31 | * @author Felix Bechstein 32 | */ 33 | public class CharacterTableSMSLengthCalculator implements SMSLengthCalculator { 34 | /** Automatic generated serial version UID. */ 35 | private static final long serialVersionUID = 750570280586096152L; 36 | 37 | /** {@link CharacterTable} used for replacing bad chars. */ 38 | private final CharacterTable mCT; 39 | 40 | /** 41 | * @param table 42 | * {@link CharacterTable} used for replacing bad chars 43 | */ 44 | public CharacterTableSMSLengthCalculator(final CharacterTable table) { 45 | this.mCT = table; 46 | } 47 | 48 | /** 49 | * @param b 50 | * {@link Bundle} for creating a {@link CharacterTable} 51 | */ 52 | public CharacterTableSMSLengthCalculator(final Bundle b) { 53 | this.mCT = new CharacterTable(b); 54 | } 55 | 56 | @Override 57 | public int[] calculateLength(final String messageBody, 58 | final boolean use7bitOnly) { 59 | return SmsMessage.calculateLength(this.mCT.encodeString(messageBody), 60 | use7bitOnly); 61 | } 62 | 63 | // Parcel stuff 64 | private CharacterTableSMSLengthCalculator(final Parcel parcel) { 65 | this(parcel.readBundle()); 66 | } 67 | 68 | public int describeContents() { 69 | return 0; 70 | } 71 | 72 | public void writeToParcel(final Parcel out, final int flags) { 73 | out.writeBundle(this.mCT.getBundle()); 74 | } 75 | 76 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 77 | public CharacterTableSMSLengthCalculator createFromParcel( 78 | final Parcel in) { 79 | return new CharacterTableSMSLengthCalculator(in); 80 | } 81 | 82 | public CharacterTableSMSLengthCalculator[] newArray(final int size) { 83 | return new CharacterTableSMSLengthCalculator[size]; 84 | } 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/Connector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.io.IOException; 22 | 23 | import android.app.Activity; 24 | import android.content.BroadcastReceiver; 25 | import android.content.Context; 26 | import android.content.Intent; 27 | import android.os.Bundle; 28 | import android.widget.Toast; 29 | 30 | /** 31 | * Receives commands coming as broadcast from WebSMS. 32 | * 33 | * @author flx 34 | */ 35 | public abstract class Connector extends BroadcastReceiver { 36 | /** Common Action prefix. */ 37 | private static final String ACTION_PREFIX = "de.ub0r." 38 | + "android.websms.connector."; 39 | 40 | /** API version. */ 41 | public static final int API_VERSION = 2; 42 | 43 | /** 44 | * Action to start a connector's Preference Activity. 45 | */ 46 | public static final String ACTION_PREFS = ".PREFS"; 47 | 48 | /** 49 | * Action to start a connector's {@link android.app.Service}. This should 50 | * include a {@link ConnectorCommand}: bootstrap. 51 | */ 52 | public static final String ACTION_RUN_BOOTSTRAP = ".RUN_BOOTSTRAP"; 53 | 54 | /** 55 | * Action to start a connector's {@link android.app.Service}. This should 56 | * include a {@link ConnectorCommand}: update. 57 | */ 58 | public static final String ACTION_RUN_UPDATE = ".RUN_UPDATE"; 59 | 60 | /** 61 | * Action to start a connector's {@link android.app.Service}. This should 62 | * include a {@link ConnectorCommand}: send. 63 | */ 64 | public static final String ACTION_RUN_SEND = ".RUN_SEND"; 65 | 66 | /** Broadcast Action requesting update of {@link ConnectorSpec}'s status. */ 67 | public static final String ACTION_CONNECTOR_UPDATE = ACTION_PREFIX 68 | + "UPDATE"; 69 | 70 | /** 71 | * Broadcast Action sending updated {@link ConnectorSpec} informations back 72 | * to WebSMS. This should include a {@link ConnectorSpec}. 73 | */ 74 | public static final String ACTION_INFO = ACTION_PREFIX + "INFO"; 75 | 76 | /** 77 | * Broadcast Action requesting to solve a captcha. Send 78 | * EXTRA_CAPTCHA_DRAWABLE and your {@link ConnectorSpec} with it. 79 | */ 80 | public static final String ACTION_CAPTCHA_REQUEST = ACTION_PREFIX 81 | + "CAPTCHA_REQUEST"; 82 | /** 83 | * Broadcast Action sending solved captcha back. The solved captcha will 84 | * come as EXTRA_CAPTCHA_SOLVED. If no Extra is given back, the user aborted 85 | * the activity. 86 | */ 87 | public static final String ACTION_CAPTCHA_SOLVED = ".CAPTCHA_SOLVED"; 88 | 89 | /** 90 | * Broadcast Action requesting to cancel a message. 91 | */ 92 | public static final String ACTION_CANCEL = ACTION_PREFIX + "CANCEL"; 93 | 94 | /** 95 | * Broadcast Action requesting to resend a message. 96 | */ 97 | public static final String ACTION_RESEND = ACTION_PREFIX + "RESEND"; 98 | 99 | /** Extra holding captcha as Drawable saved as Parcelable. */ 100 | public static final String EXTRA_CAPTCHA_DRAWABLE = "captcha"; 101 | /** Extra holding a message displayed to the user. */ 102 | public static final String EXTRA_CAPTCHA_MESSAGE = "text"; 103 | /** Extra holding the solved catpcha. */ 104 | public static final String EXTRA_CAPTCHA_SOLVED = "solved"; 105 | 106 | /** Internal {@link ConnectorSpec}. */ 107 | private static ConnectorSpec connector = null; 108 | 109 | /** Sync access to connector. */ 110 | protected static final Object SYNC_UPDATE = new Object(); 111 | 112 | /** 113 | * This instance is ran by {@link ConnectorService} via 114 | * {@link ConnectorTask}.Each implementer of this class should register 115 | * here. 116 | */ 117 | private static Connector instance = null; 118 | 119 | /** 120 | * @return single instance running all the IO in different thread. 121 | */ 122 | protected static final Connector getInstance() { 123 | if (instance == null) { 124 | throw new WebSMSException("no running Connector available"); 125 | } 126 | return instance; 127 | } 128 | 129 | /** 130 | * Register a {@link Connector} which should be ran to do all the IO in 131 | * different thread. 132 | * 133 | * @param receiver 134 | * {@link Connector} 135 | */ 136 | protected static final void registerInstance(final Connector receiver) { 137 | instance = receiver; 138 | } 139 | 140 | /** 141 | * Initialize {@link ConnectorSpec}. This is only run once. Changing 142 | * properties should be set in updateSpec(). Implement this method to 143 | * register subconnectors and set up the connector. UpdateSpec() is called 144 | * later. There is no need to duplicate code. Default implementation does 145 | * nothing at all. 146 | * 147 | * @param context 148 | * {@link Context} 149 | * @return updated {@link ConnectorSpec} 150 | */ 151 | protected ConnectorSpec initSpec(final Context context) { 152 | return new ConnectorSpec("noname"); 153 | } 154 | 155 | /** 156 | * Update {@link ConnectorSpec}. Implement this method to return the 157 | * connectors status etc. Default implementation does nothing at all. 158 | * 159 | * @param context 160 | * {@link Context} 161 | * @param connectorSpec 162 | * {@link ConnectorSpec} 163 | * @return updated {@link ConnectorSpec} 164 | */ 165 | protected ConnectorSpec updateSpec(final Context context, 166 | final ConnectorSpec connectorSpec) { 167 | return connectorSpec; 168 | } 169 | 170 | /** 171 | * Get {@link ConnectorSpec}. Initialize and update it if needed. 172 | * 173 | * @param context 174 | * {@link Context} 175 | * @return {@link ConnectorSpec} 176 | */ 177 | protected final synchronized ConnectorSpec getSpec(final Context context) { 178 | synchronized (SYNC_UPDATE) { 179 | if (connector == null) { 180 | connector = this.initSpec(context); 181 | connector.setPackage(context.getPackageName()); 182 | connector.setAPIVersion(API_VERSION); 183 | } 184 | return this.updateSpec(context, connector); 185 | } 186 | } 187 | 188 | /** 189 | * Flush everything known about the connector. 190 | */ 191 | public static final void flushSpec() { 192 | synchronized (SYNC_UPDATE) { 193 | connector = null; 194 | } 195 | } 196 | 197 | /** 198 | * Send INFO Broadcast back to WebSMS. Call this method after updating your 199 | * status, changing balance and after processing a command. 200 | * 201 | * @param context 202 | * {@link Context} 203 | * @param specs 204 | * {@link ConnectorSpec}; if null, getSpec() is called to get 205 | * them 206 | * @param command 207 | * send back the {@link ConnectorCommand} which was done 208 | */ 209 | protected final void sendInfo(final Context context, 210 | final ConnectorSpec specs, final ConnectorCommand command) { 211 | ConnectorSpec c = specs; 212 | if (c == null) { 213 | c = this.getSpec(context); 214 | } 215 | final Intent i = c.setToIntent(null); 216 | if (command != null) { 217 | command.setToIntent(i); 218 | } 219 | Log.d(this.getSpec(context).toString(), "-> bc: " + i.getAction()); 220 | context.sendBroadcast(i); 221 | } 222 | 223 | /** 224 | * This default implementation will register the running {@link Connector} 225 | * to an external service. This {@link ConnectorService} will run a 226 | * {@link ConnectorTask} running the methods doBootstrap(), doUpdate() and 227 | * doSend() implemented above. 228 | * 229 | * @param context 230 | * {@link Context} 231 | * @param intent 232 | * {@link Intent} 233 | */ 234 | @Override 235 | public void onReceive(final Context context, final Intent intent) { 236 | final ConnectorSpec specs = this.getSpec(context); 237 | final String tag = specs.toString(); 238 | final String action = intent.getAction(); 239 | Log.d(tag, "action: " + action); 240 | final String pkg = context.getPackageName(); 241 | if (action == null) { 242 | return; 243 | } 244 | if (Connector.ACTION_CONNECTOR_UPDATE.equals(action)) { 245 | Log.d(tag, "got info request"); 246 | this.sendInfo(context, null, null); 247 | // try { 248 | // this.setResultCode(Activity.RESULT_OK); 249 | // } catch (Exception e) { 250 | // Log.d(tag, "not an ordered boradcast: " + e.toString()); 251 | // } 252 | } else if (action.equals(pkg + Connector.ACTION_CAPTCHA_SOLVED)) { 253 | Log.d(tag, "got solved captcha"); 254 | final Bundle extras = intent.getExtras(); 255 | if (extras == null) { 256 | this.gotSolvedCaptcha(context, null); 257 | } else { 258 | this.gotSolvedCaptcha(context, extras 259 | .getString(EXTRA_CAPTCHA_SOLVED)); 260 | } 261 | try { 262 | this.setResultCode(Activity.RESULT_OK); 263 | } catch (Exception e) { 264 | Log.w(tag, "not an ordered boradcast: " + e.toString()); 265 | } 266 | } else if (action.equals(pkg + Connector.ACTION_RUN_BOOTSTRAP) 267 | || action.equals(pkg + Connector.ACTION_RUN_UPDATE) 268 | || action.equals(pkg + Connector.ACTION_RUN_SEND)) { 269 | Log.d(tag, "got command"); 270 | final ConnectorCommand command = ConnectorCommand.fromIntent(intent); 271 | final ConnectorSpec origSpecs = ConnectorSpec.fromIntent(intent); 272 | boolean ordered = true; 273 | if (action.equals(pkg + Connector.ACTION_RUN_UPDATE)) { 274 | ordered = false; 275 | } 276 | if (specs == null) { 277 | // skip disabled connector 278 | Log.w(tag, "specs=null"); 279 | return; 280 | } 281 | if (!specs.hasStatus(ConnectorSpec.STATUS_ENABLED)) { 282 | if (ordered) { 283 | this.setResultCode(Activity.RESULT_CANCELED); 284 | } 285 | Log.w(tag, "connector disabled"); 286 | return; 287 | } 288 | if (command == null) { 289 | // skip faulty commands 290 | Log.w(tag, "command=null"); 291 | return; 292 | } 293 | if (command.getType() != ConnectorCommand.TYPE_SEND 294 | || (origSpecs != null && specs.equals(origSpecs))) { 295 | // command type is set. 296 | // if command == send: this receiver is the wanted one. 297 | registerInstance(this); // this instance will be run by service 298 | final Intent i = new Intent(context, ConnectorService.class); 299 | i.setAction(intent.getAction()); 300 | // set command to intent 301 | command.setToIntent(i); 302 | if (origSpecs != null) { 303 | // set original specs to intent (preserve the original 304 | // specs and let ConnectorService make the decisions) 305 | origSpecs.setToIntent(i); 306 | } 307 | Log.i(tag, "start service " + i.getAction()); 308 | if (null != context.startService(i) && ordered) { 309 | // start service 310 | try { 311 | this.setResultCode(Activity.RESULT_OK); 312 | } catch (Exception e) { 313 | Log.w(tag, "not an ordered boradcast: " + e.toString()); 314 | } 315 | } 316 | } else { 317 | Log.w(tag, "faulty command:"); 318 | Log.w(tag, "command: " + command.getType()); 319 | Log.w(tag, "origSpecs: " + origSpecs); 320 | Log.w(tag, "specs: " + specs); 321 | } 322 | } 323 | } 324 | 325 | /** 326 | * Show {@link Toast} on main thread. Call this method for notifying the 327 | * user. 328 | * 329 | * @param context 330 | * {@link Context} 331 | * @param text 332 | * text 333 | */ 334 | protected final void showToast(final Context context, final String text) { 335 | if (context == null || text == null) { 336 | return; 337 | } 338 | if (context instanceof ConnectorService) { 339 | ((ConnectorService) context).showToast(text); 340 | } 341 | } 342 | 343 | /** 344 | * Do bootstrap: This method is called after each change of settings for 345 | * doing some kind of remote setup. Most connectors do not need to implement 346 | * this. Default implementation does nothing. This is executed in a 347 | * different thread! Do not do any GUI stuff. 348 | * 349 | * @param context 350 | * {@link Context} 351 | * @param intent 352 | * {@link Intent} coming from outside 353 | * @throws IOException 354 | * IOException 355 | */ 356 | protected void doBootstrap(final Context context, final Intent intent) 357 | throws IOException { 358 | // do nothing by default 359 | } 360 | 361 | /** 362 | * Do update: This method is called to update balance. Default 363 | * implementation does nothing. This is executed in a different thread! Do 364 | * not do any GUI stuff. 365 | * 366 | * @param context 367 | * {@link Context} 368 | * @param intent 369 | * {@link Intent} coming from outside 370 | * @throws IOException 371 | * IOException 372 | */ 373 | protected void doUpdate(final Context context, final Intent intent) 374 | throws IOException { 375 | // do nothing by default 376 | } 377 | 378 | /** 379 | * Do send: This method is called to send the actual message. Default 380 | * implementation does nothing. This is executed in a different thread! Do 381 | * not do any GUI stuff. 382 | * 383 | * @param context 384 | * {@link Context} 385 | * @param intent 386 | * {@link Intent} coming from outside 387 | * @throws IOException 388 | * IOException 389 | */ 390 | protected void doSend(final Context context, final Intent intent) 391 | throws IOException { 392 | // do nothing by default 393 | } 394 | 395 | /** 396 | * This method will be run, if any broadcast with a solved captcha arrived. 397 | * You should release the locks waiting for this to happen. This is not done 398 | * in the same thread as all the do* methods! 399 | * 400 | * @param context 401 | * {@link Context} 402 | * @param solvedCaptcha 403 | * the captcha solved as {@link String}, null if aborted by user. 404 | */ 405 | protected void gotSolvedCaptcha(final Context context, 406 | final String solvedCaptcha) { 407 | // do nothing by default 408 | } 409 | 410 | /** 411 | * This method is called when a new request is received. Default 412 | * implementation does nothing. This is executed in a different thread! Do 413 | * not do any GUI stuff. 414 | * 415 | * @param context 416 | * {@link Context} 417 | * @param regSpec 418 | * {@link ConnectorSpec} from the request intent 419 | * @param command 420 | * {@link ConnectorCommand} 421 | */ 422 | protected void onNewRequest(final Context context, 423 | final ConnectorSpec regSpec, final ConnectorCommand command) { 424 | // do nothing by default 425 | } 426 | 427 | } 428 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/ConnectorCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | 20 | package de.ub0r.android.websms.connector.common; 21 | 22 | import java.util.ArrayList; 23 | 24 | import android.content.Intent; 25 | import android.os.Bundle; 26 | 27 | /** 28 | * A Command send to a Connector. 29 | * 30 | * @author flx 31 | */ 32 | public final class ConnectorCommand implements Cloneable { 33 | 34 | /** Key to find command in a Bundle. */ 35 | private static final String EXTRAS_COMMAND = "command"; 36 | 37 | /** Command: type. */ 38 | private static final String TYPE = "command_type"; 39 | /** Command: type - none. */ 40 | public static final short TYPE_NONE = 0; 41 | /** Command: type - bootstrap. */ 42 | public static final short TYPE_BOOTSTRAP = 1; 43 | /** Command: type - update. */ 44 | public static final short TYPE_UPDATE = 2; 45 | /** Command: type - send. */ 46 | public static final short TYPE_SEND = 4; 47 | /** Command: message id. */ 48 | private static final String MSG_ID = "msg_id"; 49 | /** Command: default sender. */ 50 | private static final String DEFSENDER = "command_defsender"; 51 | /** Command: default prefix. */ 52 | private static final String DEFPREFIX = "command_defprefix"; 53 | /** Command: recipients. */ 54 | private static final String RECIPIENTS = "command_reciepients"; 55 | /** Command: text. */ 56 | private static final String TEXT = "command_text"; 57 | /** Command: flashsms. */ 58 | private static final String FLASHSMS = "command_flashsms"; 59 | /** Command: timestamp. */ 60 | private static final String TIMESTAMP = "command_timestamp"; 61 | /** Command: custom sender. */ 62 | private static final String CUSTOMSENDER = "command_customsender"; 63 | /** Command: list of message Uris. */ 64 | private static final String MSG_URIS = "command_msgUris"; 65 | /** Command: selected SubConnectorSpec for sending. */ 66 | private static final String SELECTEDSUBCONNECTOR = // . 67 | "command_selectedsubconnector"; 68 | /** Command: count of resend attempts. */ 69 | private static final String RESEND_COUNT = "resend_count"; 70 | 71 | /** {@link Bundle} represents the ConnectorSpec. */ 72 | private final Bundle bundle; 73 | 74 | /** 75 | * Create command with type update. 76 | * 77 | * @param defPrefix 78 | * default prefix 79 | * @param defSender 80 | * default sender 81 | * @return created command 82 | */ 83 | public static ConnectorCommand update(final String defPrefix, 84 | final String defSender) { 85 | final Bundle b = new Bundle(); 86 | b.putShort(TYPE, TYPE_UPDATE); 87 | b.putString(DEFPREFIX, defPrefix); 88 | b.putString(DEFSENDER, defSender); 89 | return new ConnectorCommand(b); 90 | } 91 | 92 | /** 93 | * Create command with type bootstrap. 94 | * 95 | * @param defPrefix 96 | * default prefix 97 | * @param defSender 98 | * default sender 99 | * @return created command 100 | */ 101 | public static ConnectorCommand bootstrap(final String defPrefix, 102 | final String defSender) { 103 | final Bundle b = new Bundle(); 104 | b.putShort(TYPE, TYPE_BOOTSTRAP); 105 | b.putString(DEFPREFIX, defPrefix); 106 | b.putString(DEFSENDER, defSender); 107 | return new ConnectorCommand(b); 108 | } 109 | 110 | /** 111 | * Create Command with type "send". 112 | * 113 | * @param msgId 114 | * unique message id 115 | * @param selectedSubConnector 116 | * selected SubConnectorSpec 117 | * @param defPrefix 118 | * default prefix 119 | * @param defSender 120 | * default sender 121 | * @param recipients 122 | * recipients 123 | * @param text 124 | * text 125 | * @param flashSMS 126 | * flashsms 127 | * @param timestamp 128 | * timestamp for sending 129 | * @param customSender 130 | * custom sender 131 | * @return created command 132 | */ 133 | public static ConnectorCommand send(final long msgId, 134 | final String selectedSubConnector, final String defPrefix, 135 | final String defSender, final String[] recipients, 136 | final String text, final boolean flashSMS, final long timestamp, 137 | final String customSender) { 138 | ConnectorCommand ret = send(msgId, selectedSubConnector, defPrefix, 139 | defSender, recipients, text, flashSMS); 140 | ret.setSendLater(timestamp); 141 | ret.setCustomSender(customSender); 142 | return ret; 143 | } 144 | 145 | /** 146 | * Create Command with type "send". 147 | * 148 | * @param msgId 149 | * unique message id 150 | * @param selectedSubConnector 151 | * selected SubConnectorSpec 152 | * @param defPrefix 153 | * default prefix 154 | * @param defSender 155 | * default sender 156 | * @param recipients 157 | * recipients 158 | * @param text 159 | * text 160 | * @param flashSMS 161 | * flashsms 162 | * @return created command 163 | */ 164 | public static ConnectorCommand send(final long msgId, 165 | final String selectedSubConnector, final String defPrefix, 166 | final String defSender, final String[] recipients, 167 | final String text, // . 168 | final boolean flashSMS) { 169 | final Bundle b = new Bundle(); 170 | b.putShort(TYPE, TYPE_SEND); 171 | b.putLong(MSG_ID, msgId); 172 | b.putString(SELECTEDSUBCONNECTOR, selectedSubConnector); 173 | b.putString(DEFPREFIX, defPrefix); 174 | b.putString(DEFSENDER, defSender); 175 | final int l = recipients.length; 176 | ArrayList r = new ArrayList(l); 177 | String s; 178 | for (int i = 0; i < l; i++) { 179 | s = recipients[i]; 180 | if (s != null && s.trim().length() > 0) { 181 | r.add(s); 182 | } 183 | } 184 | s = null; 185 | b.putStringArray(RECIPIENTS, r.toArray(new String[0])); 186 | b.putString(TEXT, text); 187 | b.putBoolean(FLASHSMS, flashSMS); 188 | b.putLong(TIMESTAMP, -1); 189 | b.putString(CUSTOMSENDER, null); 190 | return new ConnectorCommand(b); 191 | } 192 | 193 | /** 194 | * Create Command from {@link Bundle}. 195 | * 196 | * @param b 197 | * Bundle 198 | */ 199 | private ConnectorCommand(final Bundle b) { 200 | this.bundle = b; 201 | } 202 | 203 | /** 204 | * {@inheritDoc} 205 | */ 206 | @Override 207 | public Object clone() { 208 | return new ConnectorCommand((Bundle) this.bundle.clone()); 209 | } 210 | 211 | /** 212 | * Create Command from {@link Intent}. 213 | * 214 | * @param i 215 | * Intent 216 | */ 217 | public ConnectorCommand(final Intent i) { 218 | Bundle e = i.getExtras(); 219 | if (e != null) { 220 | this.bundle = e.getBundle(EXTRAS_COMMAND); 221 | } else { 222 | this.bundle = new Bundle(); 223 | } 224 | } 225 | 226 | /** 227 | * Create Command from {@link Intent}. 228 | * 229 | * @param i 230 | * Intent 231 | * @return {@link ConnectorCommand} or null if not found 232 | */ 233 | public static ConnectorCommand fromIntent(final Intent i) { 234 | Bundle bundle = i.getExtras(); 235 | if (bundle != null) { 236 | bundle = bundle.getBundle(EXTRAS_COMMAND); 237 | } 238 | if (bundle != null) { 239 | return new ConnectorCommand(bundle); 240 | } else { 241 | return null; 242 | } 243 | } 244 | 245 | /** 246 | * Set this {@link ConnectorCommand} to an {@link Intent}. Creates new 247 | * Intent if needed. 248 | * 249 | * @param intent 250 | * {@link Intent}. 251 | * @return the same {@link Intent} 252 | */ 253 | public Intent setToIntent(final Intent intent) { 254 | Intent i = intent; 255 | if (i == null) { 256 | switch (this.getType()) { 257 | case TYPE_BOOTSTRAP: 258 | i = new Intent(Connector.ACTION_RUN_BOOTSTRAP); 259 | break; 260 | case TYPE_UPDATE: 261 | i = new Intent(Connector.ACTION_RUN_UPDATE); 262 | break; 263 | case TYPE_SEND: 264 | i = new Intent(Connector.ACTION_RUN_SEND); 265 | break; 266 | default: 267 | return null; 268 | } 269 | } 270 | i.putExtra(EXTRAS_COMMAND, this.getBundle()); 271 | return i; 272 | } 273 | 274 | /** 275 | * Get internal {@link Bundle}. 276 | * 277 | * @return internal {@link Bundle} 278 | */ 279 | public Bundle getBundle() { 280 | return this.bundle; 281 | } 282 | 283 | /** 284 | * Get type. 285 | * 286 | * @return type 287 | */ 288 | public short getType() { 289 | if (this.bundle != null) { 290 | return this.bundle.getShort(TYPE); 291 | } else { 292 | return TYPE_NONE; 293 | } 294 | } 295 | 296 | /** 297 | * Get selected SubConnectorSpec. 298 | * 299 | * @return selected SubConnectorSpec 300 | */ 301 | public String getSelectedSubConnector() { 302 | if (this.bundle != null) { 303 | return this.bundle.getString(SELECTEDSUBCONNECTOR); 304 | } else { 305 | return ""; 306 | } 307 | } 308 | 309 | /** 310 | * Set selected SubConnectorSpec. 311 | * 312 | * @param selected 313 | * SubConnectorSpec 314 | */ 315 | public void setSelectedSubConnector(final String sub) { 316 | this.bundle.putString(SELECTEDSUBCONNECTOR, sub); 317 | } 318 | 319 | /** 320 | * Get default sender. 321 | * 322 | * @return default sender 323 | */ 324 | public String getDefSender() { 325 | return this.bundle.getString(DEFSENDER); 326 | } 327 | 328 | /** 329 | * Get default prefix. 330 | * 331 | * @return default prefix 332 | */ 333 | public String getDefPrefix() { 334 | return this.bundle.getString(DEFPREFIX); 335 | } 336 | 337 | /** 338 | * Set a single recipient to this command. 339 | * 340 | * @param recipient 341 | * recipient 342 | */ 343 | public void setRecipients(final String recipient) { 344 | this.bundle.putStringArray(RECIPIENTS, new String[] { recipient }); 345 | } 346 | 347 | /** 348 | * Get recipients. 349 | * 350 | * @return recipients 351 | */ 352 | public String[] getRecipients() { 353 | return this.bundle.getStringArray(RECIPIENTS); 354 | } 355 | 356 | /** 357 | * Get text. 358 | * 359 | * @return text 360 | */ 361 | public String getText() { 362 | return this.bundle.getString(TEXT); 363 | } 364 | 365 | /** 366 | * Check if message should be sent as flash sms. 367 | * 368 | * @return flashsms 369 | */ 370 | public boolean getFlashSMS() { 371 | return this.bundle.getBoolean(FLASHSMS, false); 372 | } 373 | 374 | /** 375 | * Get time of when the message should be sent. 376 | * 377 | * @return timestamp for sending 378 | */ 379 | public long getSendLater() { 380 | return this.bundle.getLong(TIMESTAMP, -1); 381 | } 382 | 383 | /** 384 | * Set timestamp for sending later. 385 | * 386 | * @param timestamp 387 | * timestamp 388 | */ 389 | public void setSendLater(final long timestamp) { 390 | this.bundle.putLong(TIMESTAMP, timestamp); 391 | } 392 | 393 | /** 394 | * Get custom sender with which the message should be sent. 395 | * 396 | * @return custom sender 397 | */ 398 | public String getCustomSender() { 399 | return this.bundle.getString(CUSTOMSENDER); 400 | } 401 | 402 | /** 403 | * Set custom sender. 404 | * 405 | * @param customSender 406 | * custom sender 407 | */ 408 | public void setCustomSender(final String customSender) { 409 | this.bundle.putString(CUSTOMSENDER, customSender); 410 | } 411 | 412 | /** 413 | * Get message Uris. 414 | * 415 | * @return message uris 416 | */ 417 | public String[] getMsgUris() { 418 | return this.bundle.getStringArray(MSG_URIS); 419 | } 420 | 421 | /** 422 | * Set message Uris. 423 | * 424 | * @param uris 425 | * uris 426 | */ 427 | public void setMsgUris(final String[] uris) { 428 | this.bundle.putStringArray(MSG_URIS, uris); 429 | } 430 | 431 | /** 432 | * Get current count of resend attempts. 433 | * 434 | * @return count of resend attempts 435 | */ 436 | public int getResendCount() { 437 | return this.bundle.getInt(RESEND_COUNT, 0); 438 | } 439 | 440 | /** 441 | * Set current count of resend attempts. 442 | * 443 | * @param resendCount 444 | * count of resend attempts 445 | */ 446 | public void setResendCount(final int resendCount) { 447 | this.bundle.putInt(RESEND_COUNT, resendCount); 448 | } 449 | 450 | /** 451 | * Get id of the linked message. 452 | * 453 | * @return message id 454 | */ 455 | public long getMsgId() { 456 | return this.bundle.getLong(MSG_ID); 457 | } 458 | 459 | /** 460 | * Compare two {@link Intent}s. 461 | * 462 | * @param i1 463 | * first intent 464 | * @param i2 465 | * second intent 466 | * @return true if both intents describe the same command 467 | */ 468 | public static boolean equals(final Intent i1, final Intent i2) { 469 | Bundle b1 = i1.getExtras(); 470 | Bundle b2 = i2.getExtras(); 471 | if (b1 == null || b2 == null) { 472 | return false; 473 | } 474 | b1 = b1.getBundle(EXTRAS_COMMAND); 475 | b2 = b2.getBundle(EXTRAS_COMMAND); 476 | if (b1 == null || b2 == null) { 477 | return false; 478 | } 479 | final short s1 = b1.getShort(TYPE); 480 | final short s2 = b2.getShort(TYPE); 481 | return s1 == s2; 482 | } 483 | } 484 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/ConnectorPreferenceActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import android.os.Build; 22 | import android.os.Bundle; 23 | import android.preference.PreferenceActivity; 24 | import android.view.MenuItem; 25 | 26 | /** 27 | * Preferences. 28 | * 29 | * @author flx 30 | */ 31 | public abstract class ConnectorPreferenceActivity extends PreferenceActivity { 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | @Override 37 | protected void onCreate(final Bundle savedInstanceState) { 38 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 39 | this.setTheme(android.R.style.Theme_Holo); 40 | } 41 | super.onCreate(savedInstanceState); 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | @Override 48 | public boolean onOptionsItemSelected(final MenuItem item) { 49 | switch (item.getItemId()) { 50 | case android.R.id.home: 51 | // app icon in Action Bar clicked; go home 52 | this.finish(); 53 | return true; 54 | default: 55 | return super.onOptionsItemSelected(item); 56 | } 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | @Override 63 | protected void onPause() { 64 | super.onPause(); 65 | Connector.flushSpec(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/ConnectorService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010-2011 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.util.ArrayList; 22 | 23 | import android.app.IntentService; 24 | import android.app.Notification; 25 | import android.app.NotificationManager; 26 | import android.app.PendingIntent; 27 | import android.content.Context; 28 | import android.content.Intent; 29 | import android.os.Handler; 30 | import android.os.Message; 31 | import android.os.PowerManager; 32 | import android.os.PowerManager.WakeLock; 33 | import android.widget.Toast; 34 | 35 | /** 36 | * {@link Service} run by the connectors BroadcastReceiver. 37 | * 38 | * @author flx 39 | */ 40 | public final class ConnectorService extends IntentService { 41 | /** Tag for output. */ 42 | private static final String TAG = "IO"; 43 | 44 | /** {@link NotificationManager}. */ 45 | private NotificationManager mNM = null; 46 | 47 | /** Notification ID of this Service. */ 48 | public static final int NOTIFICATION_PENDING = 0; 49 | 50 | /** Pending tasks. */ 51 | private final ArrayList pendingIOOps = new ArrayList(); 52 | 53 | /** {@link WakeLock} for forcing IO done before sleep. */ 54 | private WakeLock wakelock = null; 55 | 56 | /** {@link Handler}. */ 57 | private Handler handler = null; 58 | 59 | /** 60 | * Default constructor. 61 | */ 62 | public ConnectorService() { 63 | super("WebSMS.Connector"); 64 | } 65 | 66 | /** 67 | * {@inheritDoc} 68 | */ 69 | @Override 70 | public void onCreate() { 71 | super.onCreate(); 72 | this.handler = new Handler() { 73 | @Override 74 | public void handleMessage(final Message msg) { 75 | Log.i(TAG, "In handleMessage..."); 76 | } 77 | }; 78 | } 79 | 80 | /** 81 | * {@inheritDoc} 82 | */ 83 | @Override 84 | public void onStart(final Intent intent, final int startId) { 85 | Log.d(TAG, "onStart()"); 86 | if (intent != null) { 87 | this.register(intent); 88 | } 89 | // note that super.onStart will start processing the intent on the 90 | // background thread so we need to register etc before that 91 | super.onStart(intent, startId); 92 | } 93 | 94 | /** 95 | * Show {@link Toast} on main thread. 96 | * 97 | * @param text 98 | * text 99 | */ 100 | void showToast(final String text) { 101 | Log.d(TAG, "showToast(" + text + ")"); 102 | this.handler.post(new Runnable() { 103 | @Override 104 | public void run() { 105 | Toast.makeText(ConnectorService.this, text, Toast.LENGTH_LONG) 106 | .show(); 107 | } 108 | }); 109 | } 110 | 111 | /** 112 | * Build IO {@link Notification}. 113 | * 114 | * @param context 115 | * {@link Context} 116 | * @param command 117 | * {@link ConnectorCommand} 118 | * @return {@link Notification} 119 | */ 120 | public static Notification getNotification(final Context context, 121 | final ConnectorCommand command) { 122 | final String t = context.getString(R.string.stat_notify_sms_pending); 123 | final String te = context.getString(R.string.stat_notify_sending) + " " 124 | + Utils.joinRecipients(command.getRecipients(), ", "); 125 | final String tt = command.getText(); 126 | 127 | final Notification notification = new Notification( 128 | R.drawable.stat_notify_sms_pending, t, System 129 | .currentTimeMillis()); 130 | final Intent intent = new Intent(Intent.ACTION_VIEW); 131 | intent.setClassName("de.ub0r.android.websms", "WebSMS"); 132 | final PendingIntent contentIntent = PendingIntent.getActivity(context, 133 | 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 134 | notification.setLatestEventInfo(context, te, tt, contentIntent); 135 | notification.defaults |= Notification.FLAG_NO_CLEAR 136 | | Notification.FLAG_ONGOING_EVENT; 137 | notification.defaults &= Notification.DEFAULT_ALL 138 | ^ Notification.DEFAULT_LIGHTS ^ Notification.DEFAULT_SOUND 139 | ^ Notification.DEFAULT_VIBRATE; 140 | Log.d(TAG, "defaults: " + notification.defaults); 141 | return notification; 142 | } 143 | 144 | /** 145 | * Register a IO task. 146 | * 147 | * @param intent 148 | * intent holding IO operation 149 | */ 150 | private void register(final Intent intent) { 151 | Log.i(TAG, "register(" + intent.getAction() + ")"); 152 | synchronized (this.pendingIOOps) { 153 | if (this.wakelock == null) { 154 | final PowerManager pm = (PowerManager) this 155 | .getSystemService(Context.POWER_SERVICE); 156 | this.wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 157 | TAG); 158 | this.wakelock.acquire(); 159 | } 160 | final ConnectorCommand c = new ConnectorCommand(intent); 161 | if (c.getType() == ConnectorCommand.TYPE_SEND) { 162 | if (this.mNM == null) { 163 | this.mNM = (NotificationManager) this 164 | .getSystemService(NOTIFICATION_SERVICE); 165 | } 166 | try { 167 | final Notification notification = getNotification(this, c); 168 | this.mNM.notify(NOTIFICATION_PENDING, notification); 169 | } catch (IllegalArgumentException e) { 170 | Log.e(TAG, "illegal argument", e); 171 | } 172 | } 173 | Log.d(TAG, "currentIOOps=" + this.pendingIOOps.size()); 174 | this.pendingIOOps.add(intent); 175 | Log.d(TAG, "currentIOOps=" + this.pendingIOOps.size()); 176 | } 177 | } 178 | 179 | /** 180 | * Unregister a IO task. 181 | * 182 | * @param intent 183 | * intent holding IO operation 184 | */ 185 | private void unregister(final Intent intent) { 186 | Log.i(TAG, "unregister(" + intent.getAction() + ")"); 187 | synchronized (this.pendingIOOps) { 188 | Log.d(TAG, "currentIOOps=" + this.pendingIOOps.size()); 189 | final int l = this.pendingIOOps.size(); 190 | if (l == 1) { 191 | this.pendingIOOps.clear(); 192 | } else { 193 | Intent oi; 194 | for (int i = 0; i < l; i++) { 195 | oi = this.pendingIOOps.get(i); 196 | // note that ConnectorSpec.equals will not work here because 197 | // not all intent types have ConnectorSpec bundle in them 198 | if (ConnectorCommand.equals(intent, oi)) { 199 | this.pendingIOOps.remove(i); 200 | break; 201 | } 202 | } 203 | } 204 | Log.d(TAG, "currentIOOps=" + this.pendingIOOps.size()); 205 | if (this.pendingIOOps.size() == 0) { 206 | // set service to background 207 | if (this.mNM != null) { 208 | this.mNM.cancel(NOTIFICATION_PENDING); 209 | } 210 | if (this.wakelock != null && this.wakelock.isHeld()) { 211 | this.wakelock.release(); 212 | } 213 | // stop unneeded service 214 | // this.stopSelf(); 215 | } 216 | } 217 | } 218 | 219 | /** 220 | * {@inheritDoc} 221 | */ 222 | @Override 223 | public void onDestroy() { 224 | super.onDestroy(); 225 | Log.i(TAG, "onDestroy()"); 226 | Log.i(TAG, "currentIOOps=" + this.pendingIOOps.size()); 227 | final int s = this.pendingIOOps.size(); 228 | ConnectorCommand cc; 229 | ConnectorSpec cs; 230 | Intent in; 231 | for (int i = 0; i < s; i++) { 232 | cc = new ConnectorCommand(this.pendingIOOps.get(i)); 233 | cs = new ConnectorSpec(// . 234 | this.pendingIOOps.get(i)); 235 | if (cc.getType() == ConnectorCommand.TYPE_SEND) { 236 | cs.setErrorMessage("error while IO"); 237 | in = cs.setToIntent(null); 238 | cc.setToIntent(in); 239 | in.setFlags(in.getFlags() 240 | | Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 241 | this.sendBroadcast(in); 242 | in = null; 243 | } else { 244 | // Toast.makeText(this, cs.getName() + ": error while IO", 245 | // Toast.LENGTH_LONG); 246 | } 247 | } 248 | } 249 | 250 | /** 251 | * {@inheritDoc} 252 | */ 253 | @Override 254 | protected void onHandleIntent(final Intent intent) { 255 | Log.d(TAG, "onHandleIntent()"); 256 | if (intent == null) { 257 | return; 258 | } 259 | final String a = intent.getAction(); 260 | Log.d(TAG, "action: " + a); 261 | final String pkg = this.getPackageName(); 262 | if (a != null && (// . 263 | a.equals(pkg + Connector.ACTION_RUN_BOOTSTRAP) || // . 264 | a.equals(pkg + Connector.ACTION_RUN_UPDATE) || // . 265 | a.equals(pkg + Connector.ACTION_RUN_SEND))) { 266 | // register intent, if service gets killed, all pending intents 267 | // get send to websms 268 | // this.register(intent); 269 | 270 | try { 271 | final ConnectorSpec reqSpec = ConnectorSpec.fromIntent(intent); 272 | final ConnectorCommand command = new ConnectorCommand(intent); 273 | final Connector receiver = Connector.getInstance(); 274 | 275 | receiver.onNewRequest(this, reqSpec, command); 276 | 277 | ConnectorSpec respSpec = receiver.getSpec(this).clone(); 278 | 279 | this.doInBackground(intent, respSpec, command, receiver); 280 | this.onPostExecute(respSpec, command, receiver); 281 | } catch (WebSMSException e) { 282 | Log.e(TAG, "error starting service", e); 283 | // Toast.makeText(this, e.getMessage(), 284 | // Toast.LENGTH_LONG).show(); 285 | } 286 | } 287 | this.unregister(intent); 288 | } 289 | 290 | /** 291 | * Do the work in background. 292 | * 293 | * @param intent 294 | * {@link Intent} 295 | * @param respSpec 296 | * {@link ConnectorSpec} 297 | * @param command 298 | * {@link ConnectorCommand} 299 | * @param receiver 300 | * {@link Connector} 301 | */ 302 | private void doInBackground(final Intent intent, 303 | final ConnectorSpec respSpec, final ConnectorCommand command, 304 | final Connector receiver) { 305 | try { 306 | switch (command.getType()) { 307 | case ConnectorCommand.TYPE_BOOTSTRAP: 308 | receiver.doBootstrap(this, intent); 309 | break; 310 | case ConnectorCommand.TYPE_UPDATE: 311 | receiver.doUpdate(this, intent); 312 | break; 313 | case ConnectorCommand.TYPE_SEND: 314 | String t = command.getText(); 315 | String[] r = command.getRecipients(); 316 | if (t == null || t.length() == 0 || // . 317 | r == null || r.length == 0) { 318 | break; 319 | } 320 | t = null; 321 | r = null; 322 | receiver.doSend(this, intent); 323 | break; 324 | default: 325 | break; 326 | } 327 | } catch (Exception e) { 328 | if (e instanceof WebSMSException) { 329 | Log.d(TAG, respSpec.getPackage() + ": error in AsyncTask", e); 330 | } else { 331 | Log.e(TAG, respSpec.getPackage() + ": error in AsyncTask", e); 332 | } 333 | // put error message to ConnectorSpec 334 | respSpec.setErrorMessage(this, e); 335 | } 336 | } 337 | 338 | /** 339 | * Do post processing. 340 | * 341 | * @param respSpec 342 | * {@link ConnectorSpec} 343 | * @param command 344 | * {@link ConnectorCommand} 345 | * @param receiver 346 | * {@link Connector} 347 | */ 348 | private void onPostExecute(final ConnectorSpec respSpec, 349 | final ConnectorCommand command, final Connector receiver) { 350 | // final String e = connector.getErrorMessage(); 351 | // if (e != null) { 352 | // Toast.makeText(this, e, Toast.LENGTH_LONG).show(); 353 | // } 354 | respSpec.update(receiver.getSpec(this)); 355 | final Intent i = respSpec.setToIntent(null); 356 | command.setToIntent(i); 357 | i.setFlags(i.getFlags() | Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 358 | Log.d(TAG, respSpec.getPackage() + ": send broadcast info"); 359 | this.sendBroadcast(i); 360 | // this.unregister(i); 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/FakeSocketFactory.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.net.InetSocketAddress; 6 | import java.net.Socket; 7 | 8 | import javax.net.ssl.SSLContext; 9 | import javax.net.ssl.SSLSocket; 10 | import javax.net.ssl.TrustManager; 11 | 12 | import org.apache.http.conn.scheme.LayeredSocketFactory; 13 | import org.apache.http.conn.scheme.SocketFactory; 14 | import org.apache.http.params.HttpConnectionParams; 15 | import org.apache.http.params.HttpParams; 16 | 17 | /** 18 | * Fake Socket Factory. 19 | */ 20 | public final class FakeSocketFactory implements SocketFactory, 21 | LayeredSocketFactory { 22 | 23 | /** {@link SSLContext}. */ 24 | private SSLContext sslcontext = null; 25 | /** Known good fingerprints. */ 26 | private final String[] knownFingerprints; 27 | 28 | /** Default constructor. */ 29 | public FakeSocketFactory() { 30 | this((String[]) null); 31 | } 32 | 33 | /** 34 | * Constructor checking for known good fingerprints. 35 | * 36 | * @param fingerprints 37 | * known good fingerprints 38 | */ 39 | public FakeSocketFactory(final String... fingerprints) { 40 | this.knownFingerprints = fingerprints; 41 | } 42 | 43 | /** 44 | * Create a {@link SSLContext}. 45 | * 46 | * @return {@link SSLContext} 47 | * @throws IOException 48 | * IOException 49 | */ 50 | private SSLContext createEasySSLContext() throws IOException { 51 | try { 52 | SSLContext context = SSLContext.getInstance("TLS"); 53 | final TrustManager trustManager; 54 | if (this.knownFingerprints == null) { 55 | trustManager = new FakeTrustManager(); 56 | } else { 57 | trustManager = new KnownFingerprintTrustManager( 58 | this.knownFingerprints); 59 | } 60 | context.init(null, new TrustManager[] { trustManager }, null); 61 | return context; 62 | } catch (Exception e) { 63 | throw new IOException(e.getMessage()); 64 | } 65 | } 66 | 67 | /** 68 | * @return {@link SSLContext} 69 | * @throws IOException 70 | * IOException 71 | */ 72 | private SSLContext getSSLContext() throws IOException { 73 | if (this.sslcontext == null) { 74 | this.sslcontext = this.createEasySSLContext(); 75 | } 76 | return this.sslcontext; 77 | } 78 | 79 | /** 80 | * {@inheritDoc} 81 | */ 82 | @Override 83 | public Socket connectSocket(final Socket sock, final String host, 84 | final int port, final InetAddress localAddress, 85 | final int localPort, final HttpParams params) throws IOException { 86 | int connTimeout = HttpConnectionParams.getConnectionTimeout(params); 87 | int soTimeout = HttpConnectionParams.getSoTimeout(params); 88 | 89 | InetSocketAddress remoteAddress = new InetSocketAddress(host, port); 90 | SSLSocket sslsock = (SSLSocket) sock; 91 | if (sslsock == null) { 92 | this.createSocket(); 93 | } 94 | 95 | if ((localAddress != null) || (localPort > 0)) { 96 | int lp = localPort; 97 | // we need to bind explicitly 98 | if (lp < 0) { 99 | lp = 0; // indicates "any" 100 | } 101 | InetSocketAddress isa = new InetSocketAddress(localAddress, lp); 102 | sslsock.bind(isa); 103 | } 104 | 105 | sslsock.connect(remoteAddress, connTimeout); 106 | sslsock.setSoTimeout(soTimeout); 107 | return sslsock; 108 | } 109 | 110 | /** 111 | * {@inheritDoc} 112 | */ 113 | @Override 114 | public Socket createSocket() throws IOException { 115 | return this.getSSLContext().getSocketFactory().createSocket(); 116 | } 117 | 118 | /** 119 | * {@inheritDoc} 120 | */ 121 | @Override 122 | public boolean isSecure(final Socket arg0) { 123 | return true; 124 | } 125 | 126 | /** 127 | * {@inheritDoc} 128 | */ 129 | @Override 130 | public Socket createSocket(final Socket socket, final String host, 131 | final int port, final boolean autoClose) throws IOException { 132 | return this.getSSLContext().getSocketFactory().createSocket(socket, 133 | host, port, autoClose); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/FakeTrustManager.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import java.security.cert.CertificateException; 4 | import java.security.cert.X509Certificate; 5 | 6 | import javax.net.ssl.X509TrustManager; 7 | 8 | /** 9 | * All SSL certs are trusted! 10 | */ 11 | public final class FakeTrustManager implements X509TrustManager { 12 | 13 | /** ?? */ 14 | private static final X509Certificate[] _AcceptedIssuers = // . 15 | new X509Certificate[] {}; 16 | 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | @Override 21 | public void checkClientTrusted(final X509Certificate[] chain, 22 | final String authType) throws CertificateException { 23 | } 24 | 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | @Override 29 | public void checkServerTrusted(final X509Certificate[] chain, 30 | final String authType) throws CertificateException { 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | public boolean isClientTrusted(final X509Certificate[] chain) { 37 | return true; 38 | } 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public boolean isServerTrusted(final X509Certificate[] chain) { 44 | return true; 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | public X509Certificate[] getAcceptedIssuers() { 52 | return _AcceptedIssuers; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/InfoActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of ConnectorTest. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.util.List; 22 | 23 | import android.app.Activity; 24 | import android.app.AlertDialog.Builder; 25 | import android.content.ActivityNotFoundException; 26 | import android.content.DialogInterface; 27 | import android.content.Intent; 28 | import android.content.pm.ResolveInfo; 29 | import android.net.Uri; 30 | import android.os.Build; 31 | 32 | /** 33 | * This is the default Activity launched from android market after install of 34 | * any plugin. This activity simply says: "i am a plugin for WebSMS". 35 | * 36 | * @author flx 37 | */ 38 | public final class InfoActivity extends Activity { 39 | /** Tag for debug output. */ 40 | private static final String TAG = "Info"; 41 | 42 | /** Link to WebSMS in android market. */ 43 | private static final Intent INTENT_MARKET_WEBSMS = new Intent( 44 | Intent.ACTION_VIEW, Uri.parse(// . 45 | "market://search?q=pname:de.ub0r.android.websms")); 46 | 47 | /** Link to Connectors in android market. */ 48 | private static final Intent INTENT_MARKET_CONNECTORS = new Intent( 49 | Intent.ACTION_VIEW, Uri.parse(// . 50 | "market://search?q=websms+connector")); 51 | 52 | /** Info text shown to user. */ 53 | private static final String INFO_TEXT = "This is a WebSMS Connector." 54 | + "\nThe only way to use it, is lauching it with WebSMS."; 55 | 56 | /** Button label: search websms. */ 57 | private static final String BTN_MARKET_WEBSMS = "market: WebSMS"; 58 | /** Button label: search connectors. */ 59 | private static final String BTN_MARKET_CONNECTORS = // . 60 | "market: Connectors"; 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | @Override 66 | protected void onResume() { 67 | super.onResume(); 68 | Builder b; 69 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 70 | b = BuilderWrapper11.getBuilder(this, 71 | android.R.style.Theme_Holo_Light_Dialog); 72 | } else { 73 | b = new Builder(this); 74 | } 75 | b.setTitle(this.getTitle()); 76 | final String pkg = this.getPackageName(); 77 | final int info = this.getResources().getIdentifier("info_text", 78 | "string", pkg); 79 | final int icon = this.getResources().getIdentifier("icon", "drawable", 80 | pkg); 81 | Log.d(TAG, "resID.icon=" + icon); 82 | Log.d(TAG, "resID.info=" + info); 83 | if (icon > 0) { 84 | b.setIcon(icon); 85 | } 86 | if (info > 0) { 87 | b.setMessage(info); 88 | } else { 89 | b.setMessage(INFO_TEXT); 90 | } 91 | b.setPositiveButton(android.R.string.ok, 92 | new DialogInterface.OnClickListener() { 93 | @Override 94 | public void onClick(final DialogInterface dialog, 95 | final int which) { 96 | InfoActivity.this.finish(); 97 | } 98 | }); 99 | final List ri = this.getPackageManager() 100 | .queryBroadcastReceivers(new Intent(Connector.ACTION_INFO), 0); 101 | if (ri.size() == 0) { 102 | b.setNeutralButton(BTN_MARKET_WEBSMS, 103 | new DialogInterface.OnClickListener() { 104 | @Override 105 | public void onClick(final DialogInterface dialog, 106 | final int which) { 107 | try { 108 | InfoActivity.this 109 | .startActivity(INTENT_MARKET_WEBSMS); 110 | } catch (ActivityNotFoundException e) { 111 | Log.e(TAG, "no market", e); 112 | } 113 | InfoActivity.this.finish(); 114 | } 115 | }); 116 | } 117 | b.setNegativeButton(BTN_MARKET_CONNECTORS, 118 | new DialogInterface.OnClickListener() { 119 | @Override 120 | public void onClick(final DialogInterface dialog, 121 | final int which) { 122 | try { 123 | InfoActivity.this 124 | .startActivity(INTENT_MARKET_CONNECTORS); 125 | } catch (ActivityNotFoundException e) { 126 | Log.e(TAG, "no market", e); 127 | } 128 | InfoActivity.this.finish(); 129 | } 130 | }); 131 | b.setOnCancelListener(new DialogInterface.OnCancelListener() { 132 | @Override 133 | public void onCancel(final DialogInterface dialog) { 134 | InfoActivity.this.finish(); 135 | } 136 | }); 137 | b.setCancelable(true); 138 | b.show(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/KnownFingerprintTrustManager.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.cert.CertificateException; 6 | import java.security.cert.X509Certificate; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import javax.net.ssl.X509TrustManager; 12 | 13 | /** 14 | * A TrustManager-implementation that checks that a site-certificate has a known 15 | * (meaning developer-verified) fingerprint. 16 | * 17 | * @author boris 18 | */ 19 | public final class KnownFingerprintTrustManager implements X509TrustManager { 20 | 21 | /** Hex = 16 . */ 22 | private static final int HEX = 16; 23 | 24 | /** Array of known good CAs? */ 25 | private static final X509Certificate[] ACCEPTED_ISSUERS = // . 26 | new X509Certificate[] {}; 27 | 28 | /** List of known good fingerprints. */ 29 | private final List knownSha1Fingerprints; 30 | 31 | /** 32 | * @param knownFingerprints 33 | * The known fingerprint that should be used for the 34 | * check-methods 35 | * @throws NullPointerException 36 | * If {@code knownSha1Fingerprint == null} 37 | */ 38 | public KnownFingerprintTrustManager(final String... knownFingerprints) { 39 | this.knownSha1Fingerprints = new ArrayList( 40 | knownFingerprints.length); 41 | 42 | for (String fingerprint : knownFingerprints) { 43 | this.knownSha1Fingerprints.add(fingerprintToBytes(fingerprint)); 44 | } 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | @Override 51 | public void checkClientTrusted(final X509Certificate[] chain, 52 | final String authType) throws CertificateException { 53 | this.checkTrusted(chain); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | public void checkServerTrusted(final X509Certificate[] chain, 61 | final String authType) throws CertificateException { 62 | this.checkTrusted(chain); 63 | } 64 | 65 | /** 66 | * Check trusted certificate. It only checks for known good fingerprints! 67 | * 68 | * @param chain 69 | * chain of certifications 70 | * @throws CertificateException 71 | * CertificateException 72 | */ 73 | private void checkTrusted(final X509Certificate[] chain) 74 | throws CertificateException { 75 | if (chain.length == 0) { 76 | throw new CertificateException("No entries in certificate-chain"); 77 | } 78 | 79 | try { 80 | X509Certificate siteCert = chain[0]; 81 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 82 | byte[] certFingerprint = md.digest(siteCert.getEncoded()); 83 | 84 | boolean matched = false; 85 | for (byte[] fingerprint : this.knownSha1Fingerprints) { 86 | if (Arrays.equals(certFingerprint, fingerprint)) { 87 | matched = true; 88 | break; 89 | } 90 | } 91 | 92 | if (!matched) { 93 | throw new CertificateException( 94 | "Unknown certificate fingerprint " 95 | + Arrays.toString(certFingerprint)); 96 | } 97 | } catch (NoSuchAlgorithmException e) { 98 | throw new CertificateException( 99 | "Cannot calculate SHA-1 because the algorithm is missing", 100 | e); 101 | } 102 | } 103 | 104 | /** 105 | * {@inheritDoc} 106 | */ 107 | @Override 108 | public X509Certificate[] getAcceptedIssuers() { 109 | return ACCEPTED_ISSUERS; 110 | } 111 | 112 | /** 113 | * Convert fingerprint from {@link String} to {@link byte[]}. 114 | * 115 | * @param knownFingerprint 116 | * fingerprint as : separated {@link String} 117 | * @return fingerprint 118 | */ 119 | private static byte[] fingerprintToBytes(final String knownFingerprint) { 120 | final String[] byteTokens = knownFingerprint.split(":"); 121 | final byte[] result = new byte[byteTokens.length]; 122 | for (int i = 0; i < result.length; ++i) { 123 | result[i] = Integer.valueOf(byteTokens[i], HEX).byteValue(); 124 | } 125 | return result; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | 24 | import android.app.Activity; 25 | import android.app.AlertDialog; 26 | import android.content.DialogInterface; 27 | import android.content.Intent; 28 | import android.content.pm.PackageManager; 29 | import android.net.Uri; 30 | import android.text.TextUtils; 31 | 32 | /** 33 | * @author flx 34 | */ 35 | public final class Log { 36 | /** Tag for output. */ 37 | public static final String TAG = "WebSMS"; 38 | 39 | /** Packagename of SendLog. */ 40 | private static final String SENDLOG_PACKAGE_NAME = "org.l6n.sendlog"; 41 | 42 | /** Classname of SendLog. */ 43 | // private static final String SENDLOG_CLASS_NAME = ".SendLog"; 44 | 45 | /** Priority constant for the println method. */ 46 | public static final int ASSERT = android.util.Log.ASSERT; 47 | /** Priority constant for the println method; use Log.d. */ 48 | public static final int DEBUG = android.util.Log.DEBUG; 49 | /** Priority constant for the println method; use Log.e. */ 50 | public static final int ERROR = android.util.Log.ERROR; 51 | /** Priority constant for the println method; use Log.i. */ 52 | public static final int INFO = android.util.Log.INFO; 53 | /** Priority constant for the println method; use Log.v. */ 54 | public static final int VERBOSE = android.util.Log.VERBOSE; 55 | /** Priority constant for the println method; use Log.w. */ 56 | public static final int WARN = android.util.Log.WARN; 57 | 58 | /** 59 | * Fire a given {@link Intent}. 60 | * 61 | * @author flx 62 | */ 63 | private static class FireIntent implements DialogInterface.OnClickListener { 64 | /** {@link Activity}. */ 65 | private final Activity a; 66 | /** {@link Intent}. */ 67 | private final Intent i; 68 | 69 | /** 70 | * Default Constructor. 71 | * 72 | * @param activity 73 | * {@link Activity} 74 | * @param intent 75 | * {@link Intent} 76 | */ 77 | public FireIntent(final Activity activity, final Intent intent) { 78 | this.a = activity; 79 | this.i = intent; 80 | } 81 | 82 | /** 83 | * {@inheritDoc} 84 | */ 85 | public void onClick(final DialogInterface dialog, // . 86 | final int whichButton) { 87 | this.a.startActivity(this.i); 88 | } 89 | } 90 | 91 | /** 92 | * Default Constructor. 93 | */ 94 | private Log() { 95 | 96 | } 97 | 98 | /** 99 | * Send a DEBUG log message. 100 | * 101 | * @param tag 102 | * Used to identify the source of a log message. It usually 103 | * identifies the class or activity where the log call occurs. 104 | * @param msg 105 | * The message you would like logged. 106 | */ 107 | public static void d(final String tag, final String msg) { 108 | android.util.Log.d(TAG, tag + ": " + msg); 109 | } 110 | 111 | /** 112 | * Send a DEBUG log message and log the exception. 113 | * 114 | * @param tag 115 | * Used to identify the source of a log message. It usually 116 | * identifies the class or activity where the log call occurs. 117 | * @param msg 118 | * The message you would like logged. 119 | * @param tr 120 | * An exception to log. 121 | */ 122 | public static void d(final String tag, final String msg, // . 123 | final Throwable tr) { 124 | android.util.Log.d(TAG, tag + ": " + msg, tr); 125 | } 126 | 127 | /** 128 | * Send a DEBUG log message. 129 | * 130 | * @param tag 131 | * Used to identify the source of a log message. It usually 132 | * identifies the class or activity where the log call occurs. 133 | * @param msg 134 | * The message you would like logged. 135 | * @param array 136 | * array to print 137 | */ 138 | public static void d(final String tag, final String msg, 139 | final String[] array) { 140 | if (array == null) { 141 | d(tag, msg); 142 | } 143 | final StringBuilder buf = new StringBuilder(); 144 | final int l = array.length; 145 | for (int i = 0; i < l; i++) { 146 | buf.append(array[i]); 147 | if (i < l - 1) { 148 | buf.append("; "); 149 | } 150 | } 151 | android.util.Log.d(TAG, tag + ": " + msg + buf.toString()); 152 | } 153 | 154 | /** 155 | * Send a DEBUG log message. 156 | * 157 | * @param tag 158 | * Used to identify the source of a log message. It usually 159 | * identifies the class or activity where the log call occurs. 160 | * @param s 161 | * message as stream 162 | */ 163 | public static void d(final String tag, final InputStream s) { 164 | if (s == null) { 165 | d(tag, ""); 166 | } else { 167 | try { 168 | String str = Utils.stream2str(s); 169 | if (TextUtils.isEmpty(str)) { 170 | d(tag, ""); 171 | } else { 172 | String[] ss = str.split("\n"); 173 | for (String sstr : ss) { 174 | d(tag, sstr); 175 | } 176 | } 177 | } catch (IOException e) { 178 | d(tag, "", e); 179 | } 180 | } 181 | } 182 | 183 | /** 184 | * Send a ERROR log message. 185 | * 186 | * @param tag 187 | * Used to identify the source of a log message. It usually 188 | * identifies the class or activity where the log call occurs. 189 | * @param msg 190 | * The message you would like logged. 191 | */ 192 | public static void e(final String tag, final String msg) { 193 | android.util.Log.e(TAG, tag + ": " + msg); 194 | } 195 | 196 | /** 197 | * Send a ERROR log message and log the exception. 198 | * 199 | * @param tag 200 | * Used to identify the source of a log message. It usually 201 | * identifies the class or activity where the log call occurs. 202 | * @param msg 203 | * The message you would like logged. 204 | * @param tr 205 | * An exception to log. 206 | */ 207 | public static void e(final String tag, final String msg, // . 208 | final Throwable tr) { 209 | android.util.Log.e(TAG, tag + ": " + msg, tr); 210 | } 211 | 212 | /** 213 | * Send a INFO log message. 214 | * 215 | * @param tag 216 | * Used to identify the source of a log message. It usually 217 | * identifies the class or activity where the log call occurs. 218 | * @param msg 219 | * The message you would like logged. 220 | */ 221 | public static void i(final String tag, final String msg) { 222 | android.util.Log.i(TAG, tag + ": " + msg); 223 | } 224 | 225 | /** 226 | * Send a INFO log message and log the exception. 227 | * 228 | * @param tag 229 | * Used to identify the source of a log message. It usually 230 | * identifies the class or activity where the log call occurs. 231 | * @param msg 232 | * The message you would like logged. 233 | * @param tr 234 | * An exception to log. 235 | */ 236 | public static void i(final String tag, final String msg, // . 237 | final Throwable tr) { 238 | android.util.Log.i(TAG, tag + ": " + msg, tr); 239 | } 240 | 241 | /** 242 | * Send a VERBOSE log message. 243 | * 244 | * @param tag 245 | * Used to identify the source of a log message. It usually 246 | * identifies the class or activity where the log call occurs. 247 | * @param msg 248 | * The message you would like logged. 249 | */ 250 | public static void v(final String tag, final String msg) { 251 | android.util.Log.v(TAG, tag + ": " + msg); 252 | } 253 | 254 | /** 255 | * Send a VERBOSE log message and log the exception. 256 | * 257 | * @param tag 258 | * Used to identify the source of a log message. It usually 259 | * identifies the class or activity where the log call occurs. 260 | * @param msg 261 | * The message you would like logged. 262 | * @param tr 263 | * An exception to log. 264 | */ 265 | public static void v(final String tag, final String msg, // . 266 | final Throwable tr) { 267 | android.util.Log.v(TAG, tag + ": " + msg, tr); 268 | } 269 | 270 | /** 271 | * Send a WARN log message. 272 | * 273 | * @param tag 274 | * Used to identify the source of a log message. It usually 275 | * identifies the class or activity where the log call occurs. 276 | * @param msg 277 | * The message you would like logged. 278 | */ 279 | public static void w(final String tag, final String msg) { 280 | android.util.Log.w(TAG, tag + ": " + msg); 281 | } 282 | 283 | /** 284 | * Send a WARN log message and log the exception. 285 | * 286 | * @param tag 287 | * Used to identify the source of a log message. It usually 288 | * identifies the class or activity where the log call occurs. 289 | * @param msg 290 | * The message you would like logged. 291 | * @param tr 292 | * An exception to log. 293 | */ 294 | public static void w(final String tag, final String msg, // . 295 | final Throwable tr) { 296 | android.util.Log.w(TAG, tag + ": " + msg, tr); 297 | } 298 | 299 | /** 300 | * Collect and send Log. 301 | * 302 | * @param activity 303 | * {@link Activity}. 304 | */ 305 | public static void collectAndSendLog(final Activity activity) { 306 | final PackageManager packageManager = activity.getPackageManager(); 307 | Intent intent = packageManager 308 | .getLaunchIntentForPackage(SENDLOG_PACKAGE_NAME); 309 | final String pkg = activity.getPackageName(); 310 | int title, message; 311 | if (intent == null) { 312 | intent = new Intent( 313 | Intent.ACTION_VIEW, 314 | Uri.parse("market://search?q=pname:" + SENDLOG_PACKAGE_NAME)); 315 | title = activity.getResources().getIdentifier("sendlog_install_", 316 | "string", pkg); 317 | message = activity.getResources().getIdentifier("sendlog_install", 318 | "string", pkg); 319 | } else { 320 | intent.putExtra("filter", TAG + ":D *:W"); 321 | intent.setType("0||android@ub0r.de"); 322 | title = activity.getResources().getIdentifier("sendlog_run_", 323 | "string", pkg); 324 | message = activity.getResources().getIdentifier("sendlog_run", 325 | "string", pkg); 326 | } 327 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 328 | final AlertDialog.Builder b = new AlertDialog.Builder(activity); 329 | b.setIcon(android.R.drawable.ic_dialog_info); 330 | b.setTitle(title); 331 | b.setMessage(message); 332 | b.setPositiveButton(android.R.string.ok, new FireIntent(activity, 333 | intent)); 334 | b.setNegativeButton(android.R.string.cancel, null); 335 | b.show(); 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/SMSLengthCalculator.java: -------------------------------------------------------------------------------- 1 | package de.ub0r.android.websms.connector.common; 2 | 3 | import java.io.Serializable; 4 | 5 | import android.os.Parcelable; 6 | 7 | /** 8 | * A simple interface for computing the length of a message based on the message 9 | * body. This is used for informing users how many characters they have 10 | * remaining before an additional message is required, as well as how many 11 | * messages they are currently using. 12 | * 13 | * @author Fintan Fairmichael 14 | * 15 | */ 16 | public interface SMSLengthCalculator extends Serializable, Parcelable { 17 | int[] calculateLength(final String messageBody, final boolean use7bitOnly); 18 | } 19 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/WebSMSException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import android.content.Context; 22 | 23 | /** 24 | * Exception while Connector IO. 25 | * 26 | * @author flx 27 | */ 28 | public class WebSMSException extends RuntimeException { 29 | 30 | /** The Constant serialVersionUID. */ 31 | private static final long serialVersionUID = -6215729019426883487L; 32 | 33 | /** 34 | * Create a new WebSMSException. 35 | * 36 | * @param s 37 | * error message 38 | */ 39 | public WebSMSException(final String s) { 40 | super(s); 41 | } 42 | 43 | /** 44 | * Create a new {@link WebSMSException}. 45 | * 46 | * @param ex 47 | * a {@link Throwable} instance 48 | */ 49 | public WebSMSException(final Throwable ex) { 50 | super(ex); 51 | } 52 | 53 | /** 54 | * Create a new {@link WebSMSException}. 55 | * 56 | * @param ex 57 | * a {@link WebSMSException} instance 58 | */ 59 | public WebSMSException(final WebSMSException ex) { 60 | super(ex.getMessage()); 61 | } 62 | 63 | /** 64 | * Create a new WebSMSException. 65 | * 66 | * @param c 67 | * Context to resolve resource id 68 | * @param rid 69 | * error message as resource id 70 | */ 71 | public WebSMSException(final Context c, final int rid) { 72 | super(c.getString(rid)); 73 | } 74 | 75 | /** 76 | * Create a new WebSMSException. 77 | * 78 | * @param c 79 | * Context to resolve resource id 80 | * @param rid 81 | * error message as resource id 82 | * @param s 83 | * error message 84 | */ 85 | public WebSMSException(final Context c, final int rid, final String s) { 86 | super(c.getString(rid) + s); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/WebSMSNoNetworkException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | package de.ub0r.android.websms.connector.common; 20 | 21 | import android.content.Context; 22 | 23 | /** 24 | * No network available. 25 | */ 26 | public class WebSMSNoNetworkException extends WebSMSException { 27 | 28 | /** The Constant serialVersionUID. */ 29 | private static final long serialVersionUID = 8849042093428089066L; 30 | 31 | /** 32 | * Create a new WebSMSException. 33 | * 34 | * @param c 35 | * Context to resolve resource 36 | */ 37 | public WebSMSNoNetworkException(final Context c) { 38 | super(c.getString(R.string.no_network)); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Felix Bechstein 3 | * 4 | * This file is part of WebSMS. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License as published by the Free Software 8 | * Foundation; either version 3 of the License, or (at your option) any later 9 | * version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | * details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; If not, see . 18 | */ 19 | 20 | /** 21 | * This package is holding common classes for connectors. Implement new 22 | * connectors by inherent {@link Connector}. 23 | * 24 | * @version 3.0 25 | * @author flx 26 | */ 27 | package de.ub0r.android.websms.connector.common; 28 | 29 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-hdpi-v11/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-hdpi-v11/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-hdpi-v9/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-hdpi-v9/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-hdpi/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-hdpi/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-ldpi-v9/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-ldpi-v9/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-mdpi-v11/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-mdpi-v11/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-mdpi-v9/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-mdpi-v9/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-mdpi/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-mdpi/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable-xhdpi/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable-xhdpi/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable/icon.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/drawable/stat_notify_sms_pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/WebSMSAPI/src/main/res/drawable/stat_notify_sms_pending.png -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-cs/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | WebSMS Rozhraní je aplikace, kterou lze používat prostřednictvím aplikace WebSMS. 25 | WebSMS: odesílaní 26 | Odesílání: 27 | CHYBA 28 | Připojení ukončeno/vypršel časový limit. Pokud je Vaše připojení aktivní, pravděpodobně není dostupná cílová služba. Prosím zkontrolujte stránky aplikace, případně twitter. 29 | NEÚSPĚCH: HTTP 30 | Zadán neplatný email nebo heslo! 31 | Zadáno neplatné uživatelské jméno nebo heslo! 32 | Špatné číslo odesílatele. Formát musí mít mezinárodní tvar, např. +4917012345678. 33 | Odesílatel musí být registrovaný a mít ověřené číslo u poskytovatele služby. 34 | NEÚSPĚCH: Odpověď serveru: 35 | Webová služba není dostupná. Pravděpodobně se nejedná o chybu rozhraní. Prosím zkuste to později. Zkontrolujte stránky aplikace, případně twitter. 36 | Špatně vyplněný kód. Prosím zkuste to znovu. 37 | Chybě zadaný vstup! 38 | Hlavička: Chybí velikost obsahu! 39 | Maximálně 15 minut je dostupných pro Váše rozhraní! 40 | Skrýt podrozhraní \"s odesílatelem\" 41 | Skrýt podrozhraní \"s odesílatelem\" z výběru 42 | Skrýt podrozhraní \"bez odesílatele\" 43 | Skrýt podrozhraní \"bez odesílatele\" z výběru 44 | Skrýt podrozhraní \"zdarma\" 45 | Skrýt podrozhraní \"zdarma\" z výběru. 46 | Ignorovat chyby v ověření SSL 47 | Ignorovat chyby během ověření SSL. Některé telefony nemají instalovány potřebné certifikáty. Ignorování snižuje zabezpečení komunikace. 48 | Uživatelské jméno 49 | Heslo 50 | Vytvořit účet 51 | Použít výchozího odesílatele 52 | Použít výchozího odesílatele, kterého poskytuje WebSMS. 53 | Vlastní odesílatel 54 | Mez. telefonní číslo, např. +491791234567 55 | Odeslat záznamy 56 | Odeslat záznamy telefonu vývojářům. Vyberte pouze pokud jste byli požádáni. 57 | Spustit SendLog 58 | SendLog automaticky shromáždí záznamy Vašeho telefonu a odešle je vývojářům.\nBudete mít možnost tyto data prohlížet, případně měnit. 59 | Instalovat SendLog 60 | Instalovat zdarma aplikaci SendLog, která shromažďuje data a odesílá je vývojářům. 61 | Dostupný update pro rozhraní 62 | Rozhraní bylo změněno.\nPro získání nové verze klikněte prosím zde. 63 | 64 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | Diese App ist ein WebSMS Connector.\nDu kannst ihn nur mit WebSMS nutzen. 25 | WebSMS: senden 26 | Sende: 27 | FEHLER 28 | Verbindung abgebrochen/fehlgeschlagen. Wenn deine Verbindung funktioniert, ist das sehr wahrscheinlich eine Downtime des Services. Kontrolliere die Issues auf der App-Website sowie Twitter für weitere Informationen. 29 | FEHLER: HTTP 30 | Falsche Emailadresse oder Passwort angegeben! 31 | Falscher Benutzername oder Passwort angegeben! 32 | Falscher Absender! Das Format muss im internationalen Format sein, z.B. +4917012345678. 33 | Absender muss bei deinem Provider registriert und bestätigt sein. 34 | FEHLER: Serverantwort: 35 | Der Webservice ist down! Das ist sehr wahrscheinlich kein Fehler des Connectors. Bitte versuch es später noch einmal. Kontrolliere die Issues auf der App-Website sowie Twitter für weitere Informationen. 36 | Captcha war falsch. Bitte versuche es nochmal. 37 | Benutzereingabe ist falsch! 38 | Header: Content-Length fehlt! 39 | Nur volle 15 Minuten werden von deinem Provider erlaubt! 40 | Guthaben reicht nicht aus! 41 | Empfänger nicht gültig! 42 | Nachricht nicht gültig! 43 | Verstecke \"mit Absender\" SubConnector 44 | Verstecke \"mit Absender\" SubConnector in der Auswahl. 45 | Verstecke \"ohne Absender\" SubConnector 46 | Verstecke \"ohne Absender\" SubConnector in der Auswahl. 47 | Verstecke \"free\" SubConnector 48 | Verstecke \"free\" SubConnector in der Auswahl. 49 | Ignoriere SSL Handshake Fehler 50 | Ignoriere Fehler beim SSL Handshake. Einige Telefone haben nicht die benötigten Zertifikate installiert. Das Aktivieren führ zu Unsicherheiten. 51 | Benutzername 52 | Passwort 53 | Account anlegen 54 | Standard-Absender nutzen 55 | Benutze den in WebSMS eingestellten Absender. 56 | Anderer Absender 57 | Deine int. Mobilnummer, z.B. +491791234567 58 | Logs senden 59 | Logs von deinem Handy an den Entwickler senden.\nBitte nur nach Aufforderung senden. 60 | SendLog starten 61 | SendLog wird die Logs aus deinem Gerät auslesen und zum Entwickler schicken.\nDu hast vor dem Senden die Möglichkeit die Daten zu begutachten und zu verändern. 62 | SendLog installieren 63 | Installiere die kostenlose App SendLog um die Logs auszulesen und an den Entwickler zu schicken. 64 | Connector Update verfügbar 65 | Dieser Connector wird jetzt von einem anderen Entwickler betreut.\nBitte klicke hier, um den neuen Connector zu installieren. 66 | 67 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | Ceci est un connecteur WebSMS.\nLa seule manière de l\'utiliser et de le démarrer à travers WebSMS 25 | WebSMS: envoi en cours 26 | Envoi en cours: 27 | ERREUR 28 | Connexion interrompue. Si votre connexion fonctionne, le problème est probablement une interruption du service. Vérifiez le site web de l\'application et twitter pour un statut. 29 | ECHEC: HTTP 30 | Adresse mail ou mot de passe incorrect ! 31 | Nom d\'utilisateur ou mot de passe incorrect ! 32 | Expéditeur invalide ! Utilisez le format international: +4917012345678. 33 | L\'expéditeur doit être validé et confirmé par votre fournisseur de service. 34 | ECHEC : réponse du serveur : 35 | Web-Service inaccessible ! Ceci n\'est très probablement pas un problème du connecteur. Veuillez réessayer plus tard. Vérifiez le site web de l\'application et twitter pour un statut. 36 | Captcha incorrect. Veuillez réessayer. 37 | Entête: Content-Length manque ! 38 | Crédits insuffisants ! 39 | Erreur dans la saisie utilisateur ! 40 | Seuls des intervales de 15 minutes sont supportés par votre connecteur ! 41 | Destinataire invalide ! 42 | Message invalide ! 43 | Cacher le sous-connecteur \"avec expéditeur\" 44 | Cacher le sous-connecteur \"sans expéditeur\" 45 | Cacher le sous-connecteur \"avec expéditeur\" de la sélection 46 | Cacher le sous-connecteur \"sans expéditeur\" de la sélection 47 | Cacher le sous-connecteur \"gratuit\" 48 | Cacher le sous-connecteur \"gratuit\" de la sélection 49 | Ignorer les erreurs de handshake SSL 50 | Ignorer les erreurs de handshake SSL. Certains téléphones n\'ont pas les certificats nécessaires installés. Utiliser cette option n\'est pas sûr. 51 | Nom d\'utilisateur 52 | Mot de passe 53 | Créer compte 54 | Utiliser expéditeur par défaut 55 | Utiliser expéditeur par défaut défini dans WebSMS 56 | Expéditeur custom 57 | Numéro de téléphone int., p.ex. +4917912345678 58 | Envoi des logs 59 | Envoi des logs de votre téléphone au développeur.\nNe faites cela que si on vous le demande. 60 | Exécuter SendLog 61 | SendLog va collecter les logs du téléphone et les envoyer au développeur.\nVous aurez l\'opportunité de visualiser et modifier les données avant l\'envoi. 62 | Installer SendLog 63 | Installer l\'application gratuite SendLog qui permet de collecter les logs du téléphone et de les envoyer au développeur. 64 | Mise à jour du connecteur disponible 65 | Le propriétaire de ce connecteur a changé.\nVeuillez cliquer ici pour installer la nouvelle application. 66 | Aucune connexion réseau de données disponible. Vérifiez les paramètres réseau. 67 | 68 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-hu/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | Ez egy WebSMS kiegészítő.\nKizárólag a WebSMS-el együtt haszálható! 25 | WebSMS: küldés 26 | Küldés: 27 | HIBA 28 | Kapcsolat időtúllépési hiba. Ha az internetkapcsolatod működik, akkor valószínűleg a cél szerverrel van a hiba. A program honlapján és twitter accountján általában be van jelentve ha valami gond van. 29 | HIBA: HTTP 30 | Hibás email cím, vagy jelszó! 31 | Hibás email cím, vagy jelszó! 32 | Hibás címzett! Nemzetközi számformátumot használj pl.: +4917012345678. 33 | A címzettnek regisztráltnak, és visszaigazoltnak kell lennie a szolgáltatódnál. 34 | HIBA: Szerver válasz: 35 | A szolgáltatás nem elérhető! Kérem próbálkozzon később újra. 36 | Hibás Captcha. Kérlek próbálkozz újra. 37 | Hiba a felhasználó által bevitt adatokban! 38 | Fejléc: Tartalom-hossz hiányzik! 39 | Csak 15 percnyi használatot engedélyez a kiegészítőd! 40 | Elrejtés \"feladóval\" alcsatoló 41 | \"Feladóval\" alcsatoló elrejtése a listában 42 | Elrejtés \"feladó nélkül\" 43 | Feladó nélkül gomb elrejtése 44 | Elrejtés \"ingyenes\" alcsatoló 45 | \"Ingyenes\" alcsatoló elrejtése a listából 46 | Felhasználónév 47 | Jelszó 48 | Fiók létrehozása 49 | Alapértelmezett küldő használata 50 | A WebSMS által megadott alapértelmezett küldő használata. 51 | Egyedi küldő 52 | Nemzetközi telefonszám pl.: +4917912345678 53 | Logok küldése 54 | Küldd be a program napló filejait a fejlesztőnek.\nCsak akkor küld be a fileokat, ha erre felkérést kaptál. 55 | SendLog futtatása 56 | SendLog a programmal kapcsolatos log fileokat gyájti össze, majd elküldi azokat a fejlesztőnek.\nAz elküldés előtt meg lesz alkalmad a beküldendő adatok átolvasására, és szerkesztésére. 57 | SendLog telepítése 58 | Telepítsd az ingyenes SendLog alkalmazást, a napló fájlok összegyűjtéséhez, és a fejlesztőnek való elküldéséhez. 59 | Elégtelen egyenleg! 60 | Érvénytelen címzett! 61 | Érvénytelen üzenet! 62 | SSL kommunikációs hibák figyelmen kívül hagyása 63 | SSL kommunikációs hibák figyelmen kívül hagyása. Néhány telefonon nincsenek a szükséges tanúsítványok telepítve. Ezt használva nem lesz biztonságos. 64 | Connector modul frissítés elérhető 65 | A Connector modul tulajdonosa megváltozott.\nNyomjon ide, hogy telepítse az új Alkalmazást. 66 | Nem érhető el adathálózat. Ellenőrizze a hálózati beállításokat. 67 | 68 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | Questo è un Connector per WebSMS 25 | L\'unico modo per usarlo è lanciarlo con WebSMS. 26 | WebSMS: invio 27 | Invio: 28 | ERRORE 29 | Connessione terminata/scaduta. Se la connessione funziona, probabilmente si tratta di un guasto del servizio. Vedere il sito dell\'app per problemi e twitter per lo stato. 30 | Errore: HTTP 31 | Indirizzo o password errata! 32 | Nome utente o password errata! 33 | Mittente errato! Impostare nel formato internazionale. Es. +393201234567. 34 | Il mittente deve essere registrato e confermato dal provider. 35 | ERRORE: Risposta server: 36 | Il servizio web è down! Probabilmente non è un problema del Connector. Si prega di ritentare più tardi. Vedere il sito dell\'app per problemi e twitter per lo stato. 37 | Captcha errato. Ritenta. 38 | Errore nell\'immissione utente! 39 | Header: Content-Length mancante! 40 | Solo 15 minuti sono supportati dal connector! 41 | Nascondi SubConnector \"con mittente\" 42 | Nasconde il SubConnector \"con mittente\" dalla scelta. 43 | Nascondi SubConnector \"senza mittente\" 44 | Nasconde il SubConnector \"senza mittente\" dalla scelta. 45 | Nascondi SubConnector \"gratis\" 46 | Nasconde il SubConnector \"gratis\" dalla scelta. 47 | Nome utente 48 | Password 49 | Crea account 50 | Usa mittente predefinito 51 | Usa mittente predefinito su WebSMS 52 | Mittente personalizzato 53 | Numero internazionale Es. +393201234567 54 | Invia log 55 | Invia i log del dispositivo allo sviluppatore. 56 | Da fare solo se richiesto. 57 | Avvia SendLog 58 | SendLog raccoglierà i log del dispositivo e li invierà allo sviluppatore. 59 | Si avrà la possibilità di controllare e modificare i dati da inviare. 60 | Installa SendLog 61 | Installa l\'applicazione gratuita SendLog per raccogliere i log del dispositivo ed inviarli allo sviluppatore. 62 | 63 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-pt/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 20 | Este é um conector WebSMS.\nA única forma de o utilizar é com o WebSMS. 21 | WebSMS: envio... 22 | Envio: 23 | Erro 24 | A ligação foi fechada ou expirou. Se a ligação estiver a funcionar, é provável que exista um problema com o serviço. Saiba mais informações no twitter ou no sítio web da aplicação. 25 | Falha: HTTP 26 | Endereço eletrónico ou senha inválido(a)! 27 | Nome de utilizador ou senha inválido(a)! 28 | Remetente inválido! Defina um prefixo internacional válido. (Ex.:+351123456789) 29 | O remetente deve estar registado e confirmado pelo serviço. 30 | Falha: Resposta do servidor: 31 | O serviço web está desligado! Este erro não deve estar relacionado com o conector. Tente mais tarde. Saiba mais informações no twitter ou no sítio web da aplicação. 32 | Captcha inválido. Tente mais tarde. 33 | Erro nos dados introduzidos! 34 | Cabeçalho: Content-Length inexistente! 35 | Só pode utilizar este conector durante 15 minutos! 36 | Saldo insuficiente! 37 | Destinatário inválido! 38 | Mensagem inválida! 39 | Ocultar subconector \"com remetente\" 40 | Ocultar subconector \"com remetente\" da seleção. 41 | Ocultar subconector \"sem remetente\" 42 | Ocultar subconector \"sem remetente\" da seleção. 43 | Ocultar subconector \"gratuito\" da seleção. 44 | Ignorar erros SSL 45 | Ignorar erros SSL. Alguns dispositivos não possuem os certificados necesssários instalados. Esta opção comporta riscos de segurança. 46 | Nome de utilizador 47 | Senha 48 | Criar conta 49 | Utilizar remetente padrão 50 | Utilizar remetente disponibilizado pelo WebSMS. 51 | Remetente personalizado 52 | Prefixo internacional - +351123456789 53 | Enviar registos 54 | Enviar registos do dispositivo ao programador.\nNão o faça a menos que seja solicitado. 55 | Executar SendLog 56 | O SendLog irá recolher e enviar os registos do dispositivo ao programador.\nPode rever e alterar os dados enviados. 57 | Instalar SendLog 58 | Instale a aplicação SendLog para recolher e enviar os registos do dispositivo ao programador. 59 | Atualização de conector disponível 60 | A titularidade deste conector foi alterada.\nClique aqui para obter a nova aplicação. 61 | Sem rede de dados disponível. Verifique as definições de rede. 62 | Ocultar subconector \"gratuito\" 63 | 64 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-ro/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | Acesta este un Conector WebSMS.\nUnica modalitate de a-l folosi este cu ajutorul aplicației WebSMS. 25 | WebSMS: trimitere 26 | Trimitere: 27 | EROARE 28 | Conexiune terminată/întârziată. Dacă aveți o conexiune care lucrează, cel mai probabil e o problemă a serviciului țintă. Verificați situl web al aplicației sau canalul Twitter pentru statut. 29 | EȘUARE: HTTP 30 | Adresa electronică sau parola sunt greșite! 31 | Numele de utilizator sau parola sunt greșite! 32 | Expeditor invalid! Setați-l în formă internațională, spre exemplu: +37369111111. 33 | Expeditorul trebuie să fie înregistrat și confirmat de către providerul Dvs. 34 | EȘUARE: RăspunsServer: 35 | Serviciul web e inaccesibil. Mai probabil nu e problema a Conectorului. Încercați mai târziu. Verificați situl web al aplicației sau canalul Twitter pentru statut. 36 | Codul captcha e greșit. Încercați încă o dată. 37 | Eroare în textul introdus! 38 | Header: Lipsște câmpul „Content-Length”! 39 | Conectorul Dvs. suportă doar intervale de 15 minute! 40 | Ascunde SubConectorul „cu expeditor” 41 | Ascunde SubConectorul „cu expeditor” din selecție. 42 | Ascunde SubConectorul „fără expeditor” 43 | Ascunde SubConectorul „fără expeditor” din selecție. 44 | Ascunde SubConectorul „gratis” 45 | Ascunde SubConectorul „gratis” din selecție. 46 | Ignoră erorile de conectare SSL 47 | Ignoră erorile de „handshake” SSL (conectare inițială). Unor modele de telefoane le lipsesc certificatele. Opțiunea dată duce la insecuritate. 48 | Nume 49 | Parolă 50 | Creează cont 51 | Expeditor implicit 52 | Folosește expeditorul implicit din WebSMS. 53 | Expeditor modificat 54 | Număr de telefon internațional, ex.: +37369111111 55 | Trimite jurnale 56 | Trimite jurnalele folosirii aplicației către dezvoltatorul acesteia. Bifați această opțiune doar dacă ați fost rugat s-o faceți. 57 | Rulează SendLog 58 | SendLog va colecta jurnalele telefonului și le va trimite dezvoltatorului aplicației. Veți putea modifica și redacta datele înainte de a fi trimise. 59 | Instalează SendLog 60 | Instealează aplicația gratuită SendLog pentru a colecta jurnalele telefonului și a le trimite dezvoltatorului aplicației. 61 | Actualizare disponibilă 62 | Proprietarul acestui Conector s-a schimbat.\nApăsați aici pentru a instala noua Aplicație. 63 | 64 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 23 | 24 | WebSMS: Отправка 25 | Отправка: 26 | ОШИБКА 27 | ОШИБКА: HTTP 28 | Неверный e-mail адрес или пароль! 29 | Неверное имя пользователя или пароль! 30 | Неверный номер отправителя! Введите в международном формате, напр. +79261234567. 31 | Данные отправителя должны быть зарегистрированы у Вашего провайдера. 32 | ОШИБКА: Ответ сервера: 33 | Сервис не доступен! Попробуйте позже. 34 | Неверная капча. Попробуйте снова. 35 | Ошибка ввода! 36 | Заголовок: неверное содержание-длина! 37 | Ваш коннектор поддерживает только полные 15 минут! 38 | Имя пользователя 39 | Пароль 40 | Создать аккаунт 41 | Использовать отправителя по умолчанию 42 | Использовать данные отправителя по умолчанию изнастроек WebSMS. 43 | Задать отправителя 44 | Номер телефона, напр. +79261234567 45 | Отправить журналы 46 | Отправить журналы устройства разработчику.\nОтправляйте только в том случае, если Вас об этом попросят. 47 | Запустить SendLog 48 | SendLog получит журнал устройства и отправит его разработчику.\nУ Вас будет возможность просмотреть и изменить отправляемые данные. 49 | Установить SendLog 50 | Установить бесплатное приложение SendLog для получения журнала устройства и отправки его разработчику. 51 | Подключение прекращено/истекло время ожидания. Если Ваше подключение работает, то, скорее всего, не работает целевая служба. Посмотрите список проблем на веб-сайте приложения и Twitter. 52 | Недостаточный баланс! 53 | Неверный получатель! 54 | Неверное сообщение! 55 | Доступно обновление Коннектора 56 | Изменился собственник этого Коннектора.\nПожалуйста, нажмите здесь для установки нового приложения. 57 | Сеть недоступна. Проверьте настройки сети. 58 | Это WebSMS Коннектор.\nЕдинственный способ использовать его, это совместный запуск с WebSMS. 59 | Игнорировать ошибки подтверждения SSL 60 | Игнорировать ошибки во время подтверждения SSL. Некоторые телефоны не имеют необходимых установленных сертификатов. Это приводит к незащищенности. 61 | Скрыть подчиненные коннекторы \"с отправителем\" 62 | Скрыть в выбранном подчиненные коннекторы \"с отправителем\". 63 | Скрыть подчиненные коннекторы \"без отправителя\" 64 | Скрыть в выбранном подчиненные коннекторы \"без отправителя\". 65 | Скрыть \"бесплатные\" подчиненные коннекторы 66 | Скрыть в выбранном \"бесплатные\" подчиненные коннекторы. 67 | 68 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-sk/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values-tr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WebSMSAPI/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 19 | 20 | 21 | This is a WebSMS Connector.\nThe only way to use it, is lauching it with WebSMS. 22 | WebSMS: sending 23 | Sending: 24 | ERROR 25 | Connection terminated/timed out. If your connection is working, it\'s most likely a downtime of the target service. Check the app\'s website issues and twitter for status. 26 | FAILURE: HTTP 27 | Wrong mail address or password given! 28 | Wrong username or password given! 29 | Wrong sender! Set it in international form like +4917012345678. 30 | Sender must be registered and confirmed your provider. 31 | FAILURE: Serverresponse: 32 | Webservice is down! This is most likely not a problem of the connector. Please try again later. Check the app\'s website\'s issues and twitter for status. 33 | Captcha was wrong. Please try again. 34 | Error in user input! 35 | Header: Content-Length is missing! 36 | Only full 15minutes are supported by your connector! 37 | Insufficant balance! 38 | Invalid recipient! 39 | Invalid message! 40 | 41 | Hide "with sender" SubConnector 42 | Hide "with sender" SubConnector from selection. 43 | Hide "without sender" SubConnector 44 | Hide "without sender" SubConnector from selection. 45 | Hide "free" SubConnector 46 | Hide "free" SubConnector from selection. 47 | Ignore SSL handshake errors 48 | Ignore errors during SSL handshake. Some phones do not have the needed certificates installed. Using this leads to insecurity. 49 | 50 | Username 51 | Password 52 | Create account 53 | Use default sender 54 | Use default sender provided by WebSMS. 55 | Custom sender 56 | Int. phonenumber e.g. +4917912345678 57 | 58 | Send logs 59 | Send your device\'s logs to the developer.\nDo this only if you was asked to do so. 60 | Run SendLog 61 | SendLog will collect the device log and send it to the developer.\nYou will have an opportunity to review and modify the data being sent. 62 | Install SendLog 63 | Install the free SendLog application to collect the device log and send it to the developer. 64 | 65 | Connector update available 66 | The ownership of this Connector has changed.\nPlease click here, to get the new App installed. 67 | No data network available. Check your network settings. 68 | 69 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | task wrapper(type: Wrapper) { 4 | gradleVersion = '2.2.1' 5 | } 6 | -------------------------------------------------------------------------------- /doc/DeveloperFAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ for developers 2 | 3 | ## How should I install a Connector on the emulator/device? 4 | 5 | When it comes to deploying the connectors to the emulator, 6 | I just run the adb install -r from shell. 7 | I don't know, how to install it from eclipse directly, because there is no activity (in fact there is the shared info screen) to run. 8 | If someone knows a better way, please contact me. 9 | 10 | ## How do I get the running ConnectorSpec? 11 | 12 | Just use: 13 | 14 | ConnectorSpec c = this.getSpec(context); 15 | 16 | Eg. to set balance you could use this code: 17 | 18 | String balance = getBalanceFromWebService(); // TODO implement me 19 | ConnectorSpec c = this.getSpec(context); 20 | c.setBalance(balance); 21 | Log.d(TAG, "balance: " + c.getBalance()); 22 | 23 | ## In updateSpec() I get a ConnectorSpec object and I assumed that this is where I can update the balance since there is an setBalance method. As I do not have a ConnectorSpec object in doUpdate, I have to store the reference when updateSpec() initSpec() gets called and reuse it in doUpdate(). That might be the problem, but I haven't found another way so far. Is that the right method? 24 | 25 | Wrong. 26 | You must not do any network IO in `updateSpec()` or `initSpec()`. 27 | Just set the basic capabilities, features and settings in `updateSpec()` and `initSpec()`. 28 | 29 | Get the `ConnectorSpec` reference with `this.getSpec(context)` as mentioned above. 30 | 31 | ## More details 32 | 33 | See [DeveloperHelp](https://github.com/felixb/websms-api/blob/master/doc/DeveloperHelp.md) for more details. 34 | -------------------------------------------------------------------------------- /doc/DeveloperHelp.md: -------------------------------------------------------------------------------- 1 | # If you want to code your own Connector, please read this page. 2 | 3 | ## Introduction 4 | 5 | WebSMS is built modular. This makes it very easy to implement new Connectors. 6 | 7 | Each Connector is installed separately. 8 | This makes it very easy to build your own Connector and even deploy it on your own! 9 | 10 | ## API 11 | 12 | You will need the public API of WebSMS's Connector framework. 13 | 14 | For examples, just check out the code on any of the connectors hosted on [github][1]. 15 | Just pick the one, that fits you best. 16 | Some are using XML, some are using custom HTTP methods, some are using very simple HTTP APIs. 17 | 18 | Basically you just need to inherit the [Connector class][3] or even simpler the [BasicConnector class][4]. 19 | But see the example or any other Connector for more details. 20 | 21 | With all this, you should be able to build and deploy your own Connector. 22 | If something is unclear. Do not hesitate to ask me. 23 | 24 | ## Architecture 25 | 26 | Here is a sequence diagram showing how the inner communication is working: 27 | 28 | ![Seqence diagram][5] 29 | 30 | The main app is just an activity with all it's GUI and logic behind. 31 | There is nothing special. 32 | But: It is not able to communicate with any web service without a Connector. 33 | Each connector is installed as single apk (only the GSM SMS Connector is shipped with WebSMS.apk). 34 | Each connector is living in it's own context. 35 | 36 | Communication is done with [Broadcasts][6]. 37 | The WebSMS app is sending broadcast to the specific connector when running the update, bootstrap or send command, 38 | The connectors context will spawn here, if it's not alife anymore. 39 | The connector spawns (in most cases) a [Service][7], that may run in background without disturbing the user. 40 | This service runs a [AsyncTask][8] to do the network IO. 41 | At this point the API ends, this is where the `doBootstrap()`, `doUpdate()` or `doSend()` methods are called. 42 | 43 | As you might have seen, there are some more methods you could overwrite: 44 | * `initSpec()` is run once to initialisize some strings and stuff on spawning. 45 | * `getSpec()` is run, everytime it is needed. The Connector context will cache the actual instance. 46 | 47 | On startup, WebSMS will check, if the number of installed connectors has changed. 48 | If not: it will use the cached instances of all installed connectors. 49 | If it changed: it will clear the cache and run a broadcast (info request) to all connectors. 50 | They will spawn, run `initSpec()` and `getSpec()` and send back the instance to WebSMS. That's why no IO should be done in either of these methods. 51 | 52 | ## FAQ 53 | 54 | Please have a look on the [DeveloperFAQ][2]. 55 | 56 | [1]: https://github.com/felixb/ 57 | [2]: https://github.com/felixb/websms-sms/blob/master/doc/DeveloperFAQ.md 58 | [3]: https://github.com/felixb/websms-api/blob/master/WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/Connector.java 59 | [4]: https://github.com/felixb/websms-api/blob/master/WebSMSAPI/src/main/java/de/ub0r/android/websms/connector/common/BasicConnector.java 60 | [5]: https://raw.githubusercontent.com/felixb/websms-api/master/doc/sequence.png 61 | [6]: http://developer.android.com/reference/android/content/BroadcastReceiver.html 62 | [7]: http://developer.android.com/reference/android/app/Service.html 63 | [8]: http://developer.android.com/reference/android/os/AsyncTask.html 64 | -------------------------------------------------------------------------------- /doc/sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/doc/sequence.png -------------------------------------------------------------------------------- /hi-res/promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/hi-res/promo.png -------------------------------------------------------------------------------- /hi-res/promo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/hi-res/promo.xcf -------------------------------------------------------------------------------- /hi-res/websms-connector-icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/hi-res/websms-connector-icon-512x512.png -------------------------------------------------------------------------------- /hi-res/websms-connector-icon-512x512_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/hi-res/websms-connector-icon-512x512_white.png -------------------------------------------------------------------------------- /hi-res/websms-connector-icon.svgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixb/websms-api/3104ed0d2b20e9d4ec6a881f68ceaecd0ddb057a/hi-res/websms-connector-icon.svgz -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':WebSMSAPI' 2 | --------------------------------------------------------------------------------