diff --git a/src/main/scala/com/github/shadowsocks/ParserActivity.scala b/src/main/scala/com/github/shadowsocks/ParserActivity.scala index d1fcc697..009cb0d7 100644 --- a/src/main/scala/com/github/shadowsocks/ParserActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ParserActivity.scala @@ -50,9 +50,8 @@ import com.github.shadowsocks.utils.Parser class ParserActivity extends AppCompatActivity { override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) - val data = getIntent.getData.toString - val profile = Parser.parse(data) - if (profile.isEmpty) { // ignore + val profiles = Parser.findAll(getIntent.getData.toString) + if (profiles.isEmpty) { // ignore finish() return } @@ -60,11 +59,10 @@ class ParserActivity extends AppCompatActivity { val dialog = new AlertDialog.Builder(this) .setTitle(R.string.add_profile_dialog) .setCancelable(false) - .setPositiveButton(android.R.string.yes, ((dialog: DialogInterface, id: Int) => { - ShadowsocksApplication.profileManager.createProfile(profile.get) - }): DialogInterface.OnClickListener) + .setPositiveButton(android.R.string.yes, ((_, _) => + profiles.foreach(ShadowsocksApplication.profileManager.createProfile)): DialogInterface.OnClickListener) .setNegativeButton(android.R.string.no, null) - .setMessage(data) + .setMessage(profiles.mkString("\n")) .create() dialog.setOnDismissListener((dialog: DialogInterface) => finish()) // builder method was added in API 17 dialog.show() diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala index b87510d9..4df76605 100644 --- a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala @@ -212,10 +212,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) - if (scanResult != null) Parser.parse(scanResult.getContents) match { - case Some(profile) => ShadowsocksApplication.profileManager.createProfile(profile) - case _ => // ignore - } + if (scanResult != null) + Parser.findAll(scanResult.getContents).foreach(ShadowsocksApplication.profileManager.createProfile) } def onMenuItemClick(item: MenuItem) = item.getItemId match { diff --git a/src/main/scala/com/github/shadowsocks/utils/Parser.scala b/src/main/scala/com/github/shadowsocks/utils/Parser.scala index 574267a5..5ffc3eed 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Parser.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Parser.scala @@ -39,44 +39,35 @@ package com.github.shadowsocks.utils -import com.github.shadowsocks.database.Profile import java.util.Locale -import android.net.Uri -import android.util.{Log, Base64} + +import android.util.{Base64, Log} +import com.github.shadowsocks.database.Profile object Parser { val TAG = "ShadowParser" + private val pattern = "(?i)ss://([A-Za-z0-9+/=]+)".r def generate (profile: Profile): String = "ss://" + Base64.encodeToString("%s:%s@%s:%d".formatLocal(Locale.ENGLISH, profile.method, profile.password, profile.host, profile.remotePort).getBytes, Base64.NO_PADDING) - def parse (data: String): Option[Profile] = { - try { - Log.d(TAG, data) - val uri = Uri.parse(data.trim) - if (uri.getScheme == Scheme.SS) { - val encoded = data.replace(Scheme.SS + "://", "") - val content = new String(Base64.decode(encoded, Base64.NO_PADDING), "UTF-8") - val methodIdx = content.indexOf(':') - val passwordIdx = content.lastIndexOf('@') - val hostIdx = content.lastIndexOf(':') - val method = content.substring(0, methodIdx) - val password = content.substring(methodIdx + 1, passwordIdx) - val host = content.substring(passwordIdx + 1, hostIdx) - val port = content.substring(hostIdx + 1) + def findAll(data: String) = pattern.findAllMatchIn(data).map(m => try { + val content = new String(Base64.decode(m.group(1), Base64.NO_PADDING), "UTF-8") + val methodIdx = content.indexOf(':') + val passwordIdx = content.lastIndexOf('@') + val hostIdx = content.lastIndexOf(':') + val host = content.substring(passwordIdx + 1, hostIdx) - val profile = new Profile - profile.name = host - profile.host = host - profile.remotePort = port.toInt - profile.localPort = 1080 - profile.method = method.toLowerCase - profile.password = password - return Some(profile) - } - } catch { - case ex : Exception => Log.e(TAG, "parser error", ex)// Ignore - } - None - } + val profile = new Profile + profile.name = host + profile.host = host + profile.remotePort = content.substring(hostIdx + 1).toInt + profile.method = content.substring(0, methodIdx).toLowerCase + profile.password = content.substring(methodIdx + 1, passwordIdx) + profile + } catch { + case ex: Exception => + Log.e(TAG, "parser error: " + m.source, ex)// Ignore + null + }).filter(_ != null) }