package org.yaxim.androidclient.util; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.security.SecureRandom; import org.yaxim.androidclient.data.YaximConfiguration; import org.yaxim.androidclient.exceptions.YaximXMPPAdressMalformedException; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.text.Editable; import android.util.TypedValue; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcEvent; import android.os.Build; import gnu.inet.encoding.Stringprep; import gnu.inet.encoding.StringprepException; public class XMPPHelper { public static String verifyJabberID(String jid) throws YaximXMPPAdressMalformedException { try { String parts[] = jid.split("@"); if (parts.length != 2 || parts[0].length() == 0 || parts[1].length() == 0) throw new YaximXMPPAdressMalformedException( "Configured Jabber-ID is incorrect!"); StringBuilder sb = new StringBuilder(); sb.append(Stringprep.nodeprep(parts[0])); sb.append("@"); sb.append(Stringprep.nameprep(parts[1])); return sb.toString(); } catch (StringprepException spe) { throw new YaximXMPPAdressMalformedException(spe); } catch (NullPointerException e) { throw new YaximXMPPAdressMalformedException("Jabber-ID wasn't set!"); } } public static String verifyJabberID(Editable jid) throws YaximXMPPAdressMalformedException { return verifyJabberID(jid.toString()); } public static int tryToParseInt(String value, int defVal) { int ret; try { ret = Integer.parseInt(value); } catch (NumberFormatException ne) { ret = defVal; } return ret; } public static String capitalizeString(String original) { return (original.length() == 0) ? original : original.substring(0, 1).toUpperCase() + original.substring(1); } public static float getEmojiScalingFactor(String message, int length_threshold) { int offset = 0, len = message.length(); int count = 0; while (offset < len) { int cp = message.codePointAt(offset); switch (Character.getType(cp)) { // if Android doesn't know them yet: case Character.UNASSIGNED: // all smileys should be in here: case Character.OTHER_SYMBOL: count++; break; // ignore spacing and combining characters: case Character.SPACE_SEPARATOR: case Character.FORMAT: case Character.NON_SPACING_MARK: if (cp == 0x200d && count > 0) count--; // ZWJ = discount one emoji for length purposes break; default: return 1.f; } offset += Character.charCount(cp); // we do not want to have too long messages if (length_threshold > 0 && count > length_threshold) return 1.f; } if (count <= 0) // only whitespace encountered return 1.f; return 18f/(2+count); } public static int getEditTextColor(Context ctx) { TypedValue tv = new TypedValue(); boolean found = ctx.getTheme().resolveAttribute(android.R.attr.editTextColor, tv, true); if (found) { // SDK 11+ return ctx.getResources().getColor(tv.resourceId); } else { // SDK < 11 return ctx.getResources().getColor(android.R.color.primary_text_light); } } private static final String PASSWORD_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456780+-/#$!?"; private static final int PASSWORD_LENGTH = 12; public static String securePassword() { SecureRandom r = new SecureRandom(); StringBuilder sb = new StringBuilder(); for (int i = 0 ; i < PASSWORD_LENGTH; i++) sb.append(PASSWORD_CHARS.charAt(r.nextInt(PASSWORD_CHARS.length() - 1))); return sb.toString(); } // WARNING: This is not secure! This method is supposed to create a nice- // looking URL parameter for JIDs, not to encode all special characters. // This is especially important for i18n bare-JIDs which would get // mangled into URL-encoded WTF-8 public static String jid2url(String jid) { return jid.replace("%", "%25").replace("#", "%23"); } public static String createInvitationLink(String jid, String token) { StringBuilder sb = new StringBuilder(); sb.append("xmpp:").append(jid2url(jid)).append("?roster"); if (token != null && token.length() > 0) sb.append(";preauth=").append(token); return sb.toString(); } public static String createInvitationLinkHTTPS(String jid, String token) { StringBuilder sb = new StringBuilder(); sb.append("https://yax.im/i/#").append(jid2url(jid)); if (token != null && token.length() > 0) sb.append("?preauth=").append(token); return sb.toString(); } public static String createRosterLinkHTTPS(String jid) { return "https://yax.im/i/#" + jid2url(jid); } public static String createMucLinkHTTPS(String jid) { return "https://yax.im/i/#" + jid2url(jid) + "?join"; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static void setStaticNFC(Activity act, String uri) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { NfcAdapter na = NfcAdapter.getDefaultAdapter(act); if (na == null) return; NdefMessage nm = new NdefMessage(NdefRecord.createUri(uri), NdefRecord.createApplicationRecord(act.getPackageName())); na.setNdefPushMessage(nm, act); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static void setNFCInvitation(final Activity act, final YaximConfiguration config) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { NfcAdapter na = NfcAdapter.getDefaultAdapter(act); if (na == null) return; na.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() { @Override public NdefMessage createNdefMessage (NfcEvent event) { // expire NFC codes after 30mins String uri = createInvitationLink(config.jabberID, config.createInvitationCode(30*60)); return new NdefMessage(NdefRecord.createUri(uri), NdefRecord.createApplicationRecord(act.getPackageName())); } }, act); } } public static void shareLink(Activity act, int title_id, String link) { act.startActivity(Intent.createChooser(new Intent(android.content.Intent.ACTION_SEND) .setType("text/plain") .putExtra(Intent.EXTRA_TEXT, link), act.getString(title_id))); } }