diff --git a/mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt b/mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt index 314b0416..7d775eca 100644 --- a/mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt +++ b/mobile/src/main/java/com/github/shadowsocks/acl/Acl.kt @@ -52,9 +52,12 @@ class Acl { val acl = Acl() try { acl.fromId(CUSTOM_RULES) + if (!acl.bypass) { + acl.subnets.clear() + acl.hostnames.clear() + } } catch (_: FileNotFoundException) { } acl.bypass = true - acl.bypassHostnames.clear() // everything is bypassed return acl } fun save(id: String, acl: Acl) = getFile(id).writeText(acl.toString()) @@ -83,32 +86,33 @@ class Acl { @DatabaseField(generatedId = true) var id = 0 - val bypassHostnames = SortedList(String::class.java, StringSorter) - val proxyHostnames = SortedList(String::class.java, StringSorter) + val hostnames = SortedList(String::class.java, StringSorter) val subnets = SortedList(Subnet::class.java, SubnetSorter) val urls = SortedList(URL::class.java, URLSorter) @DatabaseField var bypass = false - fun fromAcl(other: Acl): Acl { - bypassHostnames.clear() - for (item in other.bypassHostnames.asIterable()) bypassHostnames.add(item) - proxyHostnames.clear() - for (item in other.proxyHostnames.asIterable()) proxyHostnames.add(item) + fun clear(): Acl { + hostnames.clear() subnets.clear() - for (item in other.subnets.asIterable()) subnets.add(item) urls.clear() + return this + } + + fun fromAcl(other: Acl): Acl { + clear() + for (item in other.hostnames.asIterable()) hostnames.add(item) + for (item in other.subnets.asIterable()) subnets.add(item) for (item in other.urls.asIterable()) urls.add(item) bypass = other.bypass return this } fun fromReader(reader: Reader, defaultBypass: Boolean = false): Acl { - bypassHostnames.clear() - proxyHostnames.clear() - subnets.clear() - urls.clear() + clear() bypass = defaultBypass + val proxyHostnames by lazy { SortedList(String::class.java, StringSorter) } + val bypassHostnames by lazy { SortedList(String::class.java, StringSorter) } val bypassSubnets by lazy { SortedList(Subnet::class.java, SubnetSorter) } val proxySubnets by lazy { SortedList(Subnet::class.java, SubnetSorter) } var hostnames: SortedList? = if (defaultBypass) proxyHostnames else bypassHostnames @@ -142,6 +146,7 @@ class Acl { } } } + for (item in (if (bypass) proxyHostnames else bypassHostnames).asIterable()) this.hostnames.add(item) for (item in (if (bypass) proxySubnets else bypassSubnets).asIterable()) this.subnets.add(item) return this } @@ -154,11 +159,12 @@ class Acl { if (bypass != child.bypass) { Log.w(TAG, "Imported network ACL has a conflicting mode set. " + "This will probably not work as intended. URL: $url") - child.subnets.clear() // subnets for the different mode are discarded + // rules for the different mode are discarded + child.hostnames.clear() + child.subnets.clear() child.bypass = bypass } - for (item in child.bypassHostnames.asIterable()) bypassHostnames.add(item) - for (item in child.proxyHostnames.asIterable()) proxyHostnames.add(item) + for (item in child.hostnames.asIterable()) hostnames.add(item) for (item in child.subnets.asIterable()) subnets.add(item) } urls.clear() @@ -167,21 +173,11 @@ class Acl { override fun toString(): String { val result = StringBuilder() - result.append(if (bypass) "[bypass_all]\n" else "[proxy_all]\n") - val bypassList = (if (bypass) bypassHostnames.asIterable().asSequence() else - subnets.asIterable().asSequence().map(Subnet::toString) + proxyHostnames.asIterable().asSequence()).toList() - val proxyList = (if (bypass) subnets.asIterable().asSequence().map(Subnet::toString) + - proxyHostnames.asIterable().asSequence() else bypassHostnames.asIterable().asSequence()).toList() - if (bypassList.isNotEmpty()) { - result.append("[bypass_list]\n") - result.append(bypassList.joinToString("\n")) - result.append('\n') - } - if (proxyList.isNotEmpty()) { - result.append("[proxy_list]\n") - result.append(proxyList.joinToString("\n")) - result.append('\n') - } + result.append(if (bypass) "[bypass_all]\n[proxy_list]\n" else "[proxy_all]\n[bypass_list]\n") + result.append(subnets.asIterable().joinToString("\n")) + result.append('\n') + result.append(hostnames.asIterable().joinToString("\n")) + result.append('\n') result.append(urls.asIterable().joinToString("") { "#IMPORT_URL <$it>\n" }) return result.toString() } diff --git a/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt b/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt index bca28fce..ac98df9c 100644 --- a/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt +++ b/mobile/src/main/java/com/github/shadowsocks/acl/CustomRulesFragment.kt @@ -132,20 +132,20 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { override fun onBindViewHolder(holder: AclRuleViewHolder, i: Int) { val j = i - acl.subnets.size() if (j < 0) holder.bind(acl.subnets[i]) else { - val k = j - acl.proxyHostnames.size() - if (k < 0) holder.bind(acl.proxyHostnames[j]) else holder.bind(acl.urls[k]) + val k = j - acl.hostnames.size() + if (k < 0) holder.bind(acl.hostnames[j]) else holder.bind(acl.urls[k]) } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = AclRuleViewHolder(LayoutInflater .from(parent.context).inflate(android.R.layout.simple_list_item_1, parent, false)) - override fun getItemCount(): Int = acl.subnets.size() + acl.proxyHostnames.size() + acl.urls.size() + override fun getItemCount(): Int = acl.subnets.size() + acl.hostnames.size() + acl.urls.size() override fun getSectionTitle(i: Int): String { val j = i - acl.subnets.size() return try { (if (j < 0) acl.subnets[i].address.hostAddress.substring(0, 1) else { - val k = j - acl.proxyHostnames.size() + val k = j - acl.hostnames.size() if (k < 0) { - val hostname = acl.proxyHostnames[j] + val hostname = acl.hostnames[j] // don't convert IDN yet PATTERN_DOMAIN.find(hostname)?.value?.replace("\\.", ".") ?: hostname } else acl.urls[k].host @@ -179,9 +179,9 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { return index } fun addHostname(hostname: String): Int { - val old = acl.proxyHostnames.size() - val index = acl.subnets.size() + acl.proxyHostnames.add(hostname) - if (old != acl.proxyHostnames.size()) { + val old = acl.hostnames.size() + val index = acl.subnets.size() + acl.hostnames.add(hostname) + if (old != acl.hostnames.size()) { notifyItemInserted(index) apply() } @@ -189,7 +189,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { } fun addURL(url: URL): Int { val old = acl.urls.size() - val index = acl.subnets.size() + acl.proxyHostnames.size() + acl.urls.add(url) + val index = acl.subnets.size() + acl.hostnames.size() + acl.urls.add(url) if (old != acl.urls.size()) { notifyItemInserted(index) apply() @@ -201,7 +201,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { var result: Int? = null if (acl.bypass) acl.subnets.asIterable().asSequence().map { addSubnet(it) } .forEach { if (result == null) result = it } - (acl.proxyHostnames.asIterable().asSequence().map { addHostname(it) } + + (acl.hostnames.asIterable().asSequence().map { addHostname(it) } + acl.urls.asIterable().asSequence().map { addURL(it) }) .forEach { if (result == null) result = it } return result @@ -227,10 +227,10 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { undoManager.remove(Pair(i, acl.subnets[i])) acl.subnets.removeItemAt(i) } else { - val k = j - acl.proxyHostnames.size() + val k = j - acl.hostnames.size() if (k < 0) { - undoManager.remove(Pair(j, acl.proxyHostnames[j])) - acl.proxyHostnames.removeItemAt(j) + undoManager.remove(Pair(j, acl.hostnames[j])) + acl.hostnames.removeItemAt(j) } else { undoManager.remove(Pair(k, acl.urls[k])) acl.urls.removeItemAt(k) @@ -247,12 +247,12 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { apply() } is String -> { - notifyItemRemoved(acl.subnets.size() + acl.proxyHostnames.indexOf(item)) - acl.proxyHostnames.remove(item) + notifyItemRemoved(acl.subnets.size() + acl.hostnames.indexOf(item)) + acl.hostnames.remove(item) apply() } is URL -> { - notifyItemRemoved(acl.subnets.size() + acl.proxyHostnames.size() + acl.urls.indexOf(item)) + notifyItemRemoved(acl.subnets.size() + acl.hostnames.size() + acl.urls.indexOf(item)) acl.urls.remove(item) apply() } @@ -271,7 +271,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { fun selectAll() { selectedItems.clear() selectedItems.addAll(acl.subnets.asIterable()) - selectedItems.addAll(acl.proxyHostnames.asIterable()) + selectedItems.addAll(acl.hostnames.asIterable()) selectedItems.addAll(acl.urls.asIterable()) onSelectedItemsUpdated() notifyDataSetChanged() @@ -386,7 +386,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { selectedItems.forEach { when (it) { is Subnet -> acl.subnets.add(it) - is String -> acl.proxyHostnames.add(it) + is String -> acl.hostnames.add(it) is URL -> acl.urls.add(it) } } @@ -432,7 +432,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener { R.id.action_import_gfwlist -> { val acl = Acl().fromId(Acl.GFWLIST) if (!acl.bypass) acl.subnets.asIterable().forEach { adapter.addSubnet(it) } - acl.proxyHostnames.asIterable().forEach { adapter.addHostname(it) } + acl.hostnames.asIterable().forEach { adapter.addHostname(it) } acl.urls.asIterable().forEach { adapter.addURL(it) } true }