diff --git a/LICENSE.md b/LICENSE.GPL2.md similarity index 100% rename from LICENSE.md rename to LICENSE.GPL2.md diff --git a/LICENSE.GPL3.md b/LICENSE.GPL3.md new file mode 100644 index 0000000000000000000000000000000000000000..44c0c9c2a6ed93eb0c089d0ddfde37e1b56e3fde --- /dev/null +++ b/LICENSE.GPL3.md @@ -0,0 +1,294 @@ +### GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +### Preamble + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at +all. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +**0.** This License applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work +based on the Program" means either the Program or any derivative work +under copyright law: that is to say, a work containing the Program or +a portion of it, either verbatim or with modifications and/or +translated into another language. (Hereinafter, translation is +included without limitation in the term "modification".) Each licensee +is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether that +is true depends on what the Program does. + +**1.** You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. + +**2.** You may modify your copy or copies of the Program or any +portion of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + +**a)** You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + + +**b)** You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any part +thereof, to be licensed as a whole at no charge to all third parties +under the terms of this License. + + +**c)** If the modified program normally reads commands interactively +when run, you must cause it, when started running for such interactive +use in the most ordinary way, to print or display an announcement +including an appropriate copyright notice and a notice that there is +no warranty (or else, saying that you provide a warranty) and that +users may redistribute the program under these conditions, and telling +the user how to view a copy of this License. (Exception: if the +Program itself is interactive but does not normally print such an +announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +**3.** You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + +**a)** Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections 1 +and 2 above on a medium customarily used for software interchange; or, + + +**b)** Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your cost of +physically performing source distribution, a complete machine-readable +copy of the corresponding source code, to be distributed under the +terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + + +**c)** Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is allowed +only for noncommercial distribution and only if you received the +program in object code or executable form with such an offer, in +accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +**4.** You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and +will automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + +**5.** You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +**6.** Each time you redistribute the Program (or any work based on +the Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +**7.** If, as a consequence of a court judgment or allegation of +patent infringement or for any other reason (not limited to patent +issues), conditions are imposed on you (whether by court order, +agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. +If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, +then as a consequence you may not distribute the Program at all. For +example, if a patent license would not permit royalty-free +redistribution of the Program by all those who receive copies directly +or indirectly through you, then the only way you could satisfy both it +and this License would be to refrain entirely from distribution of the +Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +**8.** If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +**9.** The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + +**10.** If you wish to incorporate parts of the Program into other +free programs whose distribution conditions are different, write to +the author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. + +**NO WARRANTY** + +**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +### END OF TERMS AND CONDITIONS diff --git a/README.md b/README.md index 3626ed5eba4b1adaeb2f3d5883f91ada9390ade2..42934703538be92048013faf45a156dfc0a5a9ff 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ The older implementation is still available at <https://github.com/sandsmark/Qua > This program is free software: you can redistribute it and/or modify it > under the terms of the GNU General Public License as published by the Free -> Software Foundation, either version 3 of the License, or (at your option) +> Software Foundation, either version 2 of the License, or (at your option) > any later version. > This program is distributed in the hope that it will be useful, diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt index 9ff456e538cabffe217696060b4d955557f6ac5c..4eff8cf83ac90b9ea333546de1cef8e2c01da9ec 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt @@ -10,6 +10,7 @@ import android.os.Build import de.kuschku.quasseldroid_ng.service.QuasselService import de.kuschku.quasseldroid_ng.util.AndroidCompatibilityUtils import de.kuschku.quasseldroid_ng.util.AndroidLoggingHandler +import de.kuschku.quasseldroid_ng.util.AndroidStreamChannelFactory import de.kuschku.quasseldroid_ng.util.helper.systemService import org.acra.ACRA import org.acra.ReportingInteractionMode @@ -33,8 +34,9 @@ class QuasseldroidNG : Application() { if (!ACRA.isACRASenderServiceProcess()) { // Init compatibility utils - AndroidCompatibilityUtils.init() - AndroidLoggingHandler.init() + AndroidCompatibilityUtils.inject() + AndroidLoggingHandler.inject() + AndroidStreamChannelFactory.inject() startService(Intent(this, QuasselService::class.java)) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt index 5af0e5171ec6feb98044db2e19941cf1c93101e9..933598260cd76e795b2792206865b0e3d22a1d31 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.kt @@ -15,7 +15,7 @@ import butterknife.ButterKnife import de.kuschku.libquassel.session.Backend import de.kuschku.libquassel.session.ConnectionState import de.kuschku.libquassel.session.SocketAddress -import de.kuschku.libquassel.util.LoggingHandler +import de.kuschku.libquassel.util.compatibility.LoggingHandler import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.util.helper.stickyMapNotNull import de.kuschku.quasseldroid_ng.util.helper.stickySwitchMapNotNull diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidCompatibilityUtils.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidCompatibilityUtils.kt index f3057a9720f05f088e74cd55d862c3839ca7a925..aee755bc8bfa2722a2988c681d883136b8a312d3 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidCompatibilityUtils.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidCompatibilityUtils.kt @@ -1,11 +1,11 @@ package de.kuschku.quasseldroid_ng.util import android.os.Build -import de.kuschku.libquassel.util.CompatibilityUtils +import de.kuschku.libquassel.util.compatibility.CompatibilityUtils import java.util.* object AndroidCompatibilityUtils { - fun init() { + fun inject() { /** * This is used to check if the current device supports Sockets with the KeepAlive flag. * As that feature is only missing on Chromium devices, we just check for that diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt index 8c575bc4691f509499178722f03292639e455944..c7278f3aa0b7ec588a471c9714280f645b7f349a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidHandlerService.kt @@ -3,7 +3,7 @@ package de.kuschku.quasseldroid_ng.util import android.os.Handler import android.os.HandlerThread import android.os.Process -import de.kuschku.libquassel.util.HandlerService +import de.kuschku.libquassel.util.compatibility.HandlerService class AndroidHandlerService : HandlerService { override fun parse(f: () -> Unit) { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt index 0e69d331d4bf1a98a1e7c8d0fc936ba5625107c3..bd2ebaf1d968a758434f00a3cc151c54019faa6b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidLoggingHandler.kt @@ -1,7 +1,7 @@ package de.kuschku.quasseldroid_ng.util import android.util.Log -import de.kuschku.libquassel.util.LoggingHandler +import de.kuschku.libquassel.util.compatibility.LoggingHandler object AndroidLoggingHandler : LoggingHandler() { override fun isLoggable(logLevel: LogLevel, tag: String): Boolean { @@ -25,7 +25,7 @@ object AndroidLoggingHandler : LoggingHandler() { LogLevel.ASSERT -> Log.ASSERT } - fun init() { + fun inject() { LoggingHandler.loggingHandlers.clear() LoggingHandler.loggingHandlers.add(this) } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidStreamChannelFactory.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidStreamChannelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..40ca744039284346a8bf9f291aa621cc16788ae7 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/AndroidStreamChannelFactory.kt @@ -0,0 +1,18 @@ +package de.kuschku.quasseldroid_ng.util + +import de.kuschku.libquassel.util.compatibility.StreamChannelFactory +import de.kuschku.quasseldroid_ng.util.backport.ReadableStreamChannel +import de.kuschku.quasseldroid_ng.util.backport.WritableStreamChannel +import java.io.InputStream +import java.io.OutputStream +import java.nio.channels.ReadableByteChannel +import java.nio.channels.WritableByteChannel + +object AndroidStreamChannelFactory : StreamChannelFactory { + override fun create(stream: InputStream): ReadableByteChannel = ReadableStreamChannel(stream) + override fun create(stream: OutputStream): WritableByteChannel = WritableStreamChannel(stream) + + fun inject() { + StreamChannelFactory.instance = this + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/ReadableStreamChannel.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/ReadableStreamChannel.kt new file mode 100644 index 0000000000000000000000000000000000000000..dc47a94bc4b176f18c9792e48ffc5351fbfc8527 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/ReadableStreamChannel.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package de.kuschku.quasseldroid_ng.util.backport + +import java.io.IOException +import java.io.InputStream +import java.nio.ByteBuffer +import java.nio.channels.ReadableByteChannel +import java.nio.channels.spi.AbstractInterruptibleChannel + +class ReadableStreamChannel( + private var stream: InputStream +) : AbstractInterruptibleChannel(), ReadableByteChannel { + private var buffer = ByteArray(0) + private var open = true + private val readLock = Any() + + @Throws(IOException::class) + override fun read(dst: ByteBuffer): Int { + val len = dst.remaining() + var totalRead = 0 + var bytesRead = 0 + synchronized(readLock) { + while (totalRead < len) { + val bytesToRead = Math.min(len - totalRead, + TRANSFER_SIZE) + + if (buffer.size < bytesToRead) + buffer = ByteArray(bytesToRead) + if ((totalRead > 0) && !(stream.available() > 0)) + break // block at most once + try { + begin() + bytesRead = stream.read(buffer, 0, bytesToRead) + } finally { + end(bytesRead > 0) + } + if (bytesRead < 0) + break + else + totalRead += bytesRead + dst.put(buffer, 0, bytesRead) + } + if (bytesRead < 0 && totalRead == 0) + return -1 + + return totalRead + } + } + + @Throws(IOException::class) + override fun implCloseChannel() { + stream.close() + open = false + } + + companion object { + private val TRANSFER_SIZE = 8192 + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/WritableStreamChannel.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/WritableStreamChannel.kt new file mode 100644 index 0000000000000000000000000000000000000000..4f7542301adffbadbbc6f9f6e2f7b31cebb8d621 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/backport/WritableStreamChannel.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package de.kuschku.quasseldroid_ng.util.backport + +import java.io.IOException +import java.io.OutputStream +import java.nio.ByteBuffer +import java.nio.channels.WritableByteChannel +import java.nio.channels.spi.AbstractInterruptibleChannel + + +class WritableStreamChannel( + private var stream: OutputStream +) : AbstractInterruptibleChannel(), WritableByteChannel { + private var buffer = ByteArray(0) + private var open = true + private val writeLock = Any() + + @Throws(IOException::class) + override fun write(src: ByteBuffer): Int { + val len = src.remaining() + var totalWritten = 0 + synchronized(writeLock) { + while (totalWritten < len) { + val bytesToWrite = Math.min(len - totalWritten, + TRANSFER_SIZE) + + if (buffer.size < bytesToWrite) + buffer = ByteArray(bytesToWrite) + src.get(buffer, 0, bytesToWrite) + + try { + begin() + stream.write(buffer, 0, bytesToWrite) + } finally { + end(bytesToWrite > 0) + } + totalWritten += bytesToWrite + } + return totalWritten + } + } + + @Throws(IOException::class) + override fun implCloseChannel() { + stream.close() + open = false + } + + companion object { + private val TRANSFER_SIZE = 8192 + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt index cbfd8c2060441483e98a33f993d1a40ddde0c2a3..203884d8e37aa8f6166a048b8ac3c4667ec0fca7 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/invokers/Invokers.kt @@ -2,9 +2,9 @@ package de.kuschku.libquassel.quassel.syncables.interfaces.invokers import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.quassel.syncables.interfaces.* -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN -import de.kuschku.libquassel.util.log +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.compatibility.log object Invokers { private val registry = mutableMapOf<String, Invoker<*>>() @@ -44,7 +44,8 @@ object Invokers { private fun <T> getInvoker(type: Class<T>): Invoker<T>? { val syncable: Syncable? = type.getAnnotation(Syncable::class.java) if (syncable == null) { - log(WARN, "Invokers", "Invoker not annotated: ${type.canonicalName}") + log(WARN, "Invokers", + "Invoker not annotated: ${type.canonicalName}") return null } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ConnectionState.kt b/lib/src/main/java/de/kuschku/libquassel/session/ConnectionState.kt index 1647d13cb33f093297bd6ff9a01895b0d846f345..51391c02a361636797182ef79e224200934d4599 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/ConnectionState.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/ConnectionState.kt @@ -5,5 +5,5 @@ enum class ConnectionState { CONNECTING, HANDSHAKE, INIT, - CONNECTED, + CONNECTED } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt index af42d2d4c76a471b4d47937b1f60b12215343f9a..9b26573ffa9f64f107b8c6460ab82722e62521c9 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt @@ -9,12 +9,12 @@ import de.kuschku.libquassel.protocol.primitive.serializer.IntSerializer import de.kuschku.libquassel.protocol.primitive.serializer.ProtocolSerializer import de.kuschku.libquassel.protocol.primitive.serializer.VariantListSerializer import de.kuschku.libquassel.quassel.ProtocolFeature -import de.kuschku.libquassel.util.CompatibilityUtils -import de.kuschku.libquassel.util.HandlerService -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.* +import de.kuschku.libquassel.util.compatibility.CompatibilityUtils +import de.kuschku.libquassel.util.compatibility.HandlerService +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.* +import de.kuschku.libquassel.util.compatibility.log import de.kuschku.libquassel.util.hasFlag import de.kuschku.libquassel.util.helpers.write -import de.kuschku.libquassel.util.log import de.kuschku.libquassel.util.nio.ChainedByteBuffer import de.kuschku.libquassel.util.nio.WrappedChannel import io.reactivex.BackpressureStrategy @@ -116,6 +116,7 @@ class CoreConnection( channel?.close() interrupt() handlerService.quit() + setState(ConnectionState.DISCONNECTED) } catch (e: Throwable) { log(WARN, TAG, "Error encountered while closing connection", e) } @@ -155,24 +156,23 @@ class CoreConnection( readHandshake() while (!isInterrupted) { sizeBuffer.clear() - channel?.read(sizeBuffer) + if (channel?.read(sizeBuffer) == -1) + break sizeBuffer.flip() val size = IntSerializer.deserialize(sizeBuffer, session.coreFeatures) if (size > 64 * 1024 * 1024) throw SocketException("Too large frame received: $size") val dataBuffer = ByteBuffer.allocateDirect(size) - while (!isInterrupted && dataBuffer.position() < dataBuffer.limit() && channel?.read( - dataBuffer) ?: -1 > 0) { + while (dataBuffer.position() < dataBuffer.limit() && channel?.read(dataBuffer) ?: -1 > 0) { } dataBuffer.flip() - if (!isInterrupted) - handlerService.parse { - when (internalState.value) { - ConnectionState.HANDSHAKE -> processHandshake(dataBuffer) - else -> processSigProxy(dataBuffer) - } + handlerService.parse { + when (internalState.value) { + ConnectionState.HANDSHAKE -> processHandshake(dataBuffer) + else -> processSigProxy(dataBuffer) } + } } } catch (e: Throwable) { log(WARN, TAG, "Error encountered in connection", e) diff --git a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt index e3f2b0eca8e68c3d5679619bd526e3202bf48e37..f48594eb67575206f02b6ae1d950923be6da152e 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/MessageRunnable.kt @@ -2,9 +2,9 @@ package de.kuschku.libquassel.session import de.kuschku.libquassel.protocol.Quassel_Features import de.kuschku.libquassel.protocol.primitive.serializer.Serializer -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.compatibility.log import de.kuschku.libquassel.util.helpers.write -import de.kuschku.libquassel.util.log import de.kuschku.libquassel.util.nio.ChainedByteBuffer import de.kuschku.libquassel.util.nio.WrappedChannel import java.nio.ByteBuffer diff --git a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt index 84de4de6b0c51aec9e633a79561a200f9c9a9e03..5f364a5eee0ae91d496d6b659f6ffce23edfaba4 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/ProtocolHandler.kt @@ -7,9 +7,9 @@ import de.kuschku.libquassel.quassel.exceptions.ObjectNotFoundException import de.kuschku.libquassel.quassel.syncables.RpcHandler import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.WARN -import de.kuschku.libquassel.util.log +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN +import de.kuschku.libquassel.util.compatibility.log import org.threeten.bp.Instant abstract class ProtocolHandler : SignalProxy, AuthHandler { @@ -33,7 +33,8 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { log(DEBUG, "No receiver registered for $f") } } catch (e: Throwable) { - log(WARN, "ProtocolHandler", "Error Handling SignalProxyMessage", e) + log(WARN, "ProtocolHandler", + "Error Handling SignalProxyMessage", e) } return true } @@ -44,7 +45,8 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { log(DEBUG, "No receiver registered for $f") } } catch (e: Throwable) { - log(WARN, "ProtocolHandler", "Error Handling HandshakeMessage", e) + log(WARN, "ProtocolHandler", + "Error Handling HandshakeMessage", e) } return true } @@ -170,5 +172,6 @@ abstract class ProtocolHandler : SignalProxy, AuthHandler { open fun cleanUp() { objectStorage.clear() + toInit.clear() } } diff --git a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt index 56dc9efdd5cf5516ae95256b296bd08a8758f3c3..e77a42c700f267b5c5d19809cd5c64cb038d3e6b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/Session.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/Session.kt @@ -6,11 +6,11 @@ import de.kuschku.libquassel.protocol.message.SignalProxyMessage import de.kuschku.libquassel.quassel.QuasselFeature import de.kuschku.libquassel.quassel.syncables.* import de.kuschku.libquassel.quassel.syncables.interfaces.invokers.Invokers -import de.kuschku.libquassel.util.HandlerService -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.DEBUG -import de.kuschku.libquassel.util.LoggingHandler.LogLevel.INFO +import de.kuschku.libquassel.util.compatibility.HandlerService +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG +import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO +import de.kuschku.libquassel.util.compatibility.log import de.kuschku.libquassel.util.hasFlag -import de.kuschku.libquassel.util.log import io.reactivex.BackpressureStrategy import io.reactivex.Flowable import io.reactivex.subjects.BehaviorSubject diff --git a/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt similarity index 95% rename from lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt rename to lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt index a9161802a778311fd22cb83265d2c11a70d205c1..5a44ad0024579afe0ab9420f4d7e8b08f882118f 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/CompatibilityUtils.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/CompatibilityUtils.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.compatibility import java.io.OutputStream import java.util.zip.Deflater diff --git a/lib/src/main/java/de/kuschku/libquassel/util/HandlerService.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/HandlerService.kt similarity index 78% rename from lib/src/main/java/de/kuschku/libquassel/util/HandlerService.kt rename to lib/src/main/java/de/kuschku/libquassel/util/compatibility/HandlerService.kt index 7b1334453148b580f3d3266bfc3953be6db371be..0c81b5536d867c917a2ec0b69b38daa9e0b834c5 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/HandlerService.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/HandlerService.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.compatibility interface HandlerService { fun parse(f: () -> Unit) diff --git a/lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt similarity index 96% rename from lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt rename to lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt index 43e5b29644b7262ab8e9644a51354d2360ce148b..4deee5821a49ea7f9a76881d246dd95ee0f1eb61 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/LoggingHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/LoggingHandler.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.compatibility abstract class LoggingHandler { abstract fun log(logLevel: LogLevel, tag: String, message: String? = null, diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/StreamChannelFactory.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/StreamChannelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..ee59bae56048ff21450068d43b3d5e8490f1d9dd --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/StreamChannelFactory.kt @@ -0,0 +1,18 @@ +package de.kuschku.libquassel.util.compatibility + +import de.kuschku.libquassel.util.compatibility.reference.JavaStreamChannelFactory +import java.io.InputStream +import java.io.OutputStream +import java.nio.channels.ReadableByteChannel +import java.nio.channels.WritableByteChannel + +interface StreamChannelFactory { + fun create(stream: InputStream): ReadableByteChannel + fun create(stream: OutputStream): WritableByteChannel + + companion object : StreamChannelFactory { + override fun create(stream: InputStream) = instance.create(stream) + override fun create(stream: OutputStream) = instance.create(stream) + var instance: StreamChannelFactory = JavaStreamChannelFactory + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaHandlerService.kt similarity index 90% rename from lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt rename to lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaHandlerService.kt index 4459302fd29da85e613c1fe30bf0b7c18cacb858..141780406f11fedb797c515b6a19cd727ac2a93f 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/JavaHandlerService.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaHandlerService.kt @@ -1,5 +1,6 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.compatibility.reference +import de.kuschku.libquassel.util.compatibility.HandlerService import java.util.concurrent.Executors class JavaHandlerService : HandlerService { diff --git a/lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaLoggingHandler.kt similarity index 70% rename from lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt rename to lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaLoggingHandler.kt index e6e09148d7edbcd833d6a9a858c30e0747bc0310..668d869593894048be0fbb43c887c8dd268a2655 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/JavaLoggingHandler.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaLoggingHandler.kt @@ -1,15 +1,18 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.compatibility.reference +import de.kuschku.libquassel.util.compatibility.LoggingHandler import java.util.logging.Level import java.util.logging.Logger object JavaLoggingHandler : LoggingHandler() { override fun isLoggable(logLevel: LogLevel, tag: String): Boolean { - return Logger.getLogger(tag).isLoggable(priority(logLevel)) + return Logger.getLogger(tag).isLoggable( + priority(logLevel)) } override fun log(logLevel: LogLevel, tag: String, message: String?, throwable: Throwable?) { - val priority = priority(logLevel) + val priority = priority( + logLevel) val logger = Logger.getLogger(tag) if (message != null) logger.log(priority, message) @@ -26,8 +29,8 @@ object JavaLoggingHandler : LoggingHandler() { LogLevel.ASSERT -> Level.SEVERE } - fun init() { - LoggingHandler.loggingHandlers.clear() - LoggingHandler.loggingHandlers.add(this) + fun inject() { + loggingHandlers.clear() + loggingHandlers.add(this) } } diff --git a/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaStreamChannelFactory.kt b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaStreamChannelFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..57473e492863a2b8826e8a8b675786f77c3ef9fd --- /dev/null +++ b/lib/src/main/java/de/kuschku/libquassel/util/compatibility/reference/JavaStreamChannelFactory.kt @@ -0,0 +1,17 @@ +package de.kuschku.libquassel.util.compatibility.reference + +import de.kuschku.libquassel.util.compatibility.StreamChannelFactory +import java.io.InputStream +import java.io.OutputStream +import java.nio.channels.Channels +import java.nio.channels.ReadableByteChannel +import java.nio.channels.WritableByteChannel + +object JavaStreamChannelFactory : StreamChannelFactory { + override fun create(stream: InputStream): ReadableByteChannel = Channels.newChannel(stream) + override fun create(stream: OutputStream): WritableByteChannel = Channels.newChannel(stream) + + fun inject() { + StreamChannelFactory.instance = this + } +} diff --git a/lib/src/main/java/de/kuschku/libquassel/util/helpers/StringHelper.kt b/lib/src/main/java/de/kuschku/libquassel/util/helpers/StringHelper.kt index 59f2985a71fd47d88afc6bf191eb27aee0e6a43b..bd4f543fd88ce561a30268db3f05a5db3f8b29be 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/helpers/StringHelper.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/helpers/StringHelper.kt @@ -5,8 +5,4 @@ package de.kuschku.libquassel.util.helpers * * @return A list with all substrings of length 1, in order */ -fun String.split(): Array<String> { - val chars = arrayOfNulls<String>(length) - val charArray = toCharArray() - return chars.indices.map { String(charArray, it, 1) }.toTypedArray() -} +fun String.split() = Array(length) { this.substring(it, it + 1) } diff --git a/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt b/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt index 1896f5f90da3dbe9657394e5dcd92155a8109376..1170202b27c27cb0b2dd7b15878eaba14eb26401 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/nio/WrappedChannel.kt @@ -1,7 +1,8 @@ package de.kuschku.libquassel.util.nio import de.kuschku.libquassel.session.SocketAddress -import de.kuschku.libquassel.util.CompatibilityUtils +import de.kuschku.libquassel.util.compatibility.CompatibilityUtils +import de.kuschku.libquassel.util.compatibility.StreamChannelFactory import java.io.Flushable import java.io.IOException import java.io.InputStream @@ -9,7 +10,10 @@ import java.io.OutputStream import java.net.Socket import java.net.SocketException import java.nio.ByteBuffer -import java.nio.channels.* +import java.nio.channels.ByteChannel +import java.nio.channels.InterruptibleChannel +import java.nio.channels.ReadableByteChannel +import java.nio.channels.WritableByteChannel import java.security.GeneralSecurityException import java.util.zip.InflaterInputStream import javax.net.ssl.SSLContext @@ -19,16 +23,21 @@ import javax.net.ssl.X509TrustManager class WrappedChannel( private val socket: Socket, - private val rawInStream: InputStream? = null, - private val rawOutStream: OutputStream? = null, + private var rawInStream: InputStream? = null, + private var rawOutStream: OutputStream? = null, private var flusher: (() -> Unit)? = null ) : Flushable, ByteChannel, InterruptibleChannel { private var rawIn: ReadableByteChannel? = null private var rawOut: WritableByteChannel? = null init { - this.rawIn = Channels.newChannel(rawInStream) - this.rawOut = Channels.newChannel(rawOutStream) + val rawInStream = this.rawInStream + if (rawInStream != null) + this.rawIn = StreamChannelFactory.create(rawInStream) + + val rawOutStream = this.rawOutStream + if (rawOutStream != null) + this.rawOut = StreamChannelFactory.create(rawOutStream) } companion object { diff --git a/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt index 6ea74866617dd22a6c1aafe5f75212b38f6c7a59..08de3201d0593736ff52d89e93ca469a50fe6d53 100644 --- a/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt +++ b/lib/src/test/java/de/kuschku/libquassel/ConnectionUnitTest.kt @@ -9,8 +9,8 @@ import de.kuschku.libquassel.quassel.QuasselFeature import de.kuschku.libquassel.session.CoreConnection import de.kuschku.libquassel.session.Session import de.kuschku.libquassel.session.SocketAddress -import de.kuschku.libquassel.util.JavaHandlerService -import de.kuschku.libquassel.util.JavaLoggingHandler +import de.kuschku.libquassel.util.compatibility.reference.JavaHandlerService +import de.kuschku.libquassel.util.compatibility.reference.JavaLoggingHandler import org.junit.BeforeClass import org.junit.Test import org.threeten.bp.Instant @@ -53,7 +53,8 @@ class ConnectionUnitTest { session.userData = user to pass session.connection.onNext( - CoreConnection(session, SocketAddress(host, port), JavaHandlerService())) + CoreConnection(session, SocketAddress(host, port), + JavaHandlerService())) session.connection.value.start() session.connection.value.join() }