Skip to content
Snippets Groups Projects
Commit fd47bd8d authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Rewrote all Syncables and the structure of the libquassel Client object

Updated README and licenses.
parent 877077d8
No related branches found
No related tags found
No related merge requests found
Showing
with 1058 additions and 653 deletions
GNU Lesser General Public License
=================================
_Version 3, 29 June 2007_
_Copyright © 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;_
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
### 0. Additional Definitions
As used herein, “this License” refers to version 3 of the GNU Lesser
General Public License, and the “GNU GPL” refers to version 3 of the GNU
General Public License.
“The Library” refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An “Application” is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A “Combined Work” is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the “Linked
Version”.
The “Minimal Corresponding Source” for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The “Corresponding Application Code” for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
### 1. Exception to Section 3 of the GNU GPL
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
### 2. Conveying Modified Versions
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
* **a)** under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
* **b)** under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
### 3. Object Code Incorporating Material from Library Header Files
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
* **a)** Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
* **b)** Accompany the object code with a copy of the GNU GPL and this license
document.
### 4. Combined Works
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
* **a)** Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
* **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
document.
* **c)** For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
* **d)** Do one of the following:
- **0)** Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- **1)** Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that **(a)** uses at run time
a copy of the Library already present on the user's computer
system, and **(b)** will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
* **e)** Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option **4d0**, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option **4d1**, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
### 5. Combined Libraries
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
* **a)** Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
* **b)** Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
### 6. Revised Versions of the GNU Lesser General Public License
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser 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
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License “or any later version”
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
......@@ -104,15 +104,12 @@ just yet.
> 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)
> any later version, or under the terms of the GNU Lesser General Public
> License as published by the Free Software Foundation; either version 2.1 of
> the License, or (at your option) any later version.
> any later version.
> This program 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 for more details.
> You should have received a copy of the GNU General Public License and the
> GNU Lesser General Public License along with this program. If not, see
> &lt;<http://www.gnu.org/licenses/>&gt;.
> You should have received a copy of the GNU General Public License along
> with this program. If not, see &lt;<http://www.gnu.org/licenses/>&gt;.
......@@ -8,18 +8,15 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
......@@ -148,7 +145,7 @@ dependencies {
// UI Libs
compile(name:'library-release', ext:'aar')
compile('com.mikepenz:materialdrawer:5.0.0.b21-SNAPSHOT@aar') { transitive = true }
compile('com.mikepenz:materialdrawer:5.0.0.b24-SNAPSHOT@aar') { transitive = true }
compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') { transitive = true }
compile('com.github.afollestad.material-dialogs:commons:0.8.5.3@aar') { transitive = true }
......
......@@ -9,26 +9,25 @@
~ 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)
~ any later version, or under the terms of the GNU Lesser General Public
~ License as published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~ any later version.
~
~ This program 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 for more details.
~
~ You should have received a copy of the GNU General Public License and the
~ GNU Lesser General Public License along with this program. If not, see
~ <http://www.gnu.org/licenses/>.
~ You should have received a copy of the GNU General Public License along
~ with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.kuschku.quasseldroid_ng">
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".QuasselDroidNG"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/appName"
......
......@@ -8,18 +8,15 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
......
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.LagChangedEvent;
import de.kuschku.libquassel.events.StatusMessageEvent;
import de.kuschku.libquassel.functions.types.HandshakeFunction;
import de.kuschku.libquassel.functions.types.InitRequestFunction;
import de.kuschku.libquassel.functions.types.RpcCallFunction;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.localtypes.Buffers;
import de.kuschku.libquassel.localtypes.NotificationManager;
import de.kuschku.libquassel.localtypes.backlogmanagers.BacklogManager;
import de.kuschku.libquassel.localtypes.backlogmanagers.SimpleBacklogManager;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.objects.types.ClientInitAck;
import de.kuschku.libquassel.objects.types.ClientLogin;
import de.kuschku.libquassel.objects.types.SessionState;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.types.BufferSyncer;
import de.kuschku.libquassel.syncables.types.BufferViewManager;
import de.kuschku.libquassel.syncables.types.Identity;
import de.kuschku.libquassel.syncables.types.IgnoreListManager;
import de.kuschku.libquassel.syncables.types.IrcChannel;
import de.kuschku.libquassel.syncables.types.IrcUser;
import de.kuschku.libquassel.syncables.types.Network;
import de.kuschku.libquassel.syncables.types.SyncableObject;
import de.kuschku.util.backports.Stream;
import de.kuschku.util.observables.lists.ObservableElementList;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class Client {
@NonNull
private final Map<Integer, Network> networks = new HashMap<>();
@NonNull
private final ObservableElementList<Integer> networkList = new ObservableElementList<>();
@NonNull
private final Map<Integer, Buffer> buffers = new HashMap<>();
@NonNull
private final List<String> initDataQueue = new ArrayList<>();
@NonNull
private final BacklogManager backlogManager;
@NonNull
private final NotificationManager notificationManager = new NotificationManager(this);
@NonNull
private final BusProvider busProvider;
private long lag;
@NonNull
private ConnectionChangeEvent.Status connectionStatus = ConnectionChangeEvent.Status.DISCONNECTED;
@Nullable
private ClientInitAck core;
@Nullable
private SessionState state;
@Nullable
private BufferViewManager bufferViewManager;
@Nullable
private BufferSyncer bufferSyncer;
@Nullable
private IgnoreListManager ignoreListManager;
@NonNull
private final Map<Integer, Identity> Identities = new HashMap<>();
public Client(@NonNull final BusProvider busProvider) {
this(new SimpleBacklogManager(busProvider), busProvider);
}
public Client(@NonNull final BacklogManager backlogManager, @NonNull final BusProvider busProvider) {
this.backlogManager = backlogManager;
this.busProvider = busProvider;
this.backlogManager.setClient(this);
}
public void sendInput(@NonNull final BufferInfo info, @NonNull final String input) {
busProvider.dispatch(new RpcCallFunction(
"2sendInput(BufferInfo,QString)",
new QVariant<>(info),
new QVariant<>(input)
));
}
public void displayMsg(@NonNull final Message message) {
backlogManager.displayMessage(message.bufferInfo.id, message);
}
public void displayStatusMsg(@NonNull String scope, @NonNull String message) {
busProvider.sendEvent(new StatusMessageEvent(scope, message));
}
public void putNetwork(@NonNull final Network network) {
assertNotNull(state);
networks.put(network.getNetworkId(), network);
networkList.add(network.getNetworkId());
for (BufferInfo info : state.BufferInfos) {
if (info.networkId == network.getNetworkId()) {
Buffer buffer = Buffers.fromType(info, network);
assertNotNull(buffer);
putBuffer(buffer);
}
}
}
@Nullable
public Network getNetwork(final int networkId) {
return this.networks.get(networkId);
}
public void putBuffer(@NonNull final Buffer buffer) {
this.buffers.put(buffer.getInfo().id, buffer);
this.notificationManager.init(buffer.getInfo().id);
}
@Nullable
public Buffer getBuffer(final int bufferId) {
return this.buffers.get(bufferId);
}
public void sendInitRequest(@NonNull final String className, @Nullable final String objectName) {
sendInitRequest(className, objectName, false);
}
public void sendInitRequest(@NonNull final String className, @Nullable final String objectName, boolean addToList) {
busProvider.dispatch(new InitRequestFunction(className, objectName));
if (addToList)
getInitDataQueue().add(className + ":" + objectName);
}
public void __objectRenamed__(@NonNull String className, @NonNull String newName, @NonNull String oldName) {
safeGetObjectByIdentifier(className, oldName).renameObject(newName);
}
@NonNull
private SyncableObject safeGetObjectByIdentifier(@NonNull String className, @NonNull String oldName) {
SyncableObject val = getObjectByIdentifier(className, oldName);
if (val == null)
throw new IllegalArgumentException(String.format("Object %s::%s does not exist", className, oldName));
else return val;
}
@Nullable
public SyncableObject getObjectByIdentifier(@NonNull final String className, @Nullable final String objectName) {
switch (className) {
case "BacklogManager":
return getBacklogManager();
case "IrcChannel": {
assertNotNull(objectName);
final int networkId = Integer.parseInt(objectName.split("/")[0]);
final String channelname = objectName.split("/")[1];
// Assert that networkId is valid
Network network = getNetwork(networkId);
assertNotNull(network);
IrcChannel channel = network.getChannels().get(channelname);
assertNotNull("Channel " + channelname + " not found in " + network.getChannels().keySet(), channel);
return channel;
}
case "BufferSyncer":
return bufferSyncer;
case "BufferViewConfig":
assertNotNull(getBufferViewManager());
assertNotNull(objectName);
return getBufferViewManager().BufferViews.get(Integer.valueOf(objectName));
case "IrcUser": {
assertNotNull(objectName);
final int networkId = Integer.parseInt(objectName.split("/")[0]);
final String username = objectName.split("/")[1];
Network network = getNetwork(networkId);
assertNotNull(network);
IrcUser networkUser = network.getUser(username);
assertNotNull("User " + username + " not found in " + network.getUsers().keySet(), networkUser);
return networkUser;
}
case "Network": {
assertNotNull(objectName);
return getNetwork(Integer.parseInt(objectName));
}
default:
throw new IllegalArgumentException(String.format("No object of type %s known: %s", className, objectName));
}
}
@Nullable
public SessionState getState() {
return state;
}
public void setState(@Nullable SessionState state) {
this.state = state;
Log.e("DEBUG", String.valueOf(this.state));
}
@NonNull
public List<String> getInitDataQueue() {
return initDataQueue;
}
@NonNull
public BacklogManager<?> getBacklogManager() {
return backlogManager;
}
@Nullable
public BufferViewManager getBufferViewManager() {
return bufferViewManager;
}
public void setBufferViewManager(@NonNull final BufferViewManager bufferViewManager) {
this.bufferViewManager = bufferViewManager;
for (int id : bufferViewManager.BufferViews.keySet()) {
sendInitRequest("BufferViewConfig", String.valueOf(id), true);
}
}
@Nullable
public BufferSyncer getBufferSyncer() {
return bufferSyncer;
}
public void setBufferSyncer(@Nullable BufferSyncer bufferSyncer) {
this.bufferSyncer = bufferSyncer;
}
@Nullable
public ClientInitAck getCore() {
return core;
}
public void setCore(@Nullable ClientInitAck core) {
this.core = core;
}
@NonNull
public Collection<Buffer> getBuffers(int networkId) {
return new Stream<>(this.buffers.values()).filter(buffer -> buffer.getInfo().networkId == networkId).list();
}
@NonNull
public ObservableElementList<Integer> getNetworks() {
return networkList;
}
@NonNull
public ConnectionChangeEvent.Status getConnectionStatus() {
return connectionStatus;
}
public void setConnectionStatus(@NonNull final ConnectionChangeEvent.Status connectionStatus) {
this.connectionStatus = connectionStatus;
busProvider.sendEvent(new ConnectionChangeEvent(connectionStatus));
}
public void login(@NonNull String username, @NonNull String password) {
busProvider.dispatch(new HandshakeFunction(new ClientLogin(
username, password
)));
}
@NonNull
public NotificationManager getNotificationManager() {
return notificationManager;
}
public long getLag() {
return lag;
}
public void setLag(long l) {
lag = l;
busProvider.sendEvent(new LagChangedEvent(lag));
}
@Nullable
public IgnoreListManager getIgnoreListManager() {
return ignoreListManager;
}
public void setIgnoreListManager(@Nullable IgnoreListManager ignoreListManager) {
this.ignoreListManager = ignoreListManager;
}
public void addIdentity(int id, Identity identity) {
Identities.put(id, identity);
}
public Identity getIdentity(int id) {
return Identities.get(id);
}
}
......@@ -8,18 +8,15 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
......@@ -40,6 +37,8 @@ import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import de.kuschku.libquassel.client.ClientData;
import de.kuschku.libquassel.client.QClient;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.GeneralErrorEvent;
import de.kuschku.libquassel.events.HandshakeFailedEvent;
......@@ -75,6 +74,10 @@ public class CoreConnection {
private final ClientData clientData;
@NonNull
private final BusProvider busProvider;
@NonNull
private final QClient client;
@NonNull
private final CertificateManager certificateManager;
@Nullable
private ExecutorService outputExecutor;
@Nullable
......@@ -89,15 +92,16 @@ public class CoreConnection {
private Socket socket;
@NonNull
private ConnectionChangeEvent.Status status = ConnectionChangeEvent.Status.DISCONNECTED;
@Nullable
private Client client;
@NonNull
private final CertificateManager certificateManager;
public CoreConnection(@NonNull final ServerAddress address, @NonNull final ClientData clientData, @NonNull final BusProvider busProvider, @NonNull CertificateManager certificateManager) {
public CoreConnection(@NonNull final ServerAddress address,
@NonNull final ClientData clientData,
@NonNull final BusProvider busProvider,
@NonNull final QClient client,
@NonNull CertificateManager certificateManager) {
this.address = address;
this.clientData = clientData;
this.busProvider = busProvider;
this.client = client;
this.certificateManager = certificateManager;
}
......@@ -115,6 +119,9 @@ public class CoreConnection {
public void open(boolean supportsKeepAlive) throws IOException {
assertNotNull(client);
status = ConnectionChangeEvent.Status.HANDSHAKE;
client.setConnectionStatus(status);
// Intialize socket
socket = new Socket();
if (supportsKeepAlive) socket.setKeepAlive(true);
......@@ -124,7 +131,6 @@ public class CoreConnection {
channel = WrappedChannel.ofSocket(socket);
busProvider.event.register(this);
client.setConnectionStatus(ConnectionChangeEvent.Status.HANDSHAKE);
// Create executor for write events
outputExecutor = Executors.newSingleThreadExecutor();
......@@ -209,8 +215,10 @@ public class CoreConnection {
this.close();
}
public void onEventAsync(@NonNull ConnectionChangeEvent event) {
public void onEvent(@NonNull ConnectionChangeEvent event) {
this.status = event.status;
if (event.status == ConnectionChangeEvent.Status.INITIALIZING_DATA && heartbeatThread != null)
heartbeatThread.start();
}
public void setCompression(boolean supportsCompression) {
......@@ -233,10 +241,6 @@ public class CoreConnection {
}
}
public void setClient(@NonNull Client client) {
this.client = client;
}
/**
* A runnable that reads from the channel and calls the functions responsible for processing the read data.
*/
......@@ -283,7 +287,6 @@ public class CoreConnection {
// Mark prehandshake as read
hasReadPreHandshake = true;
assertNotNull(heartbeatThread);
heartbeatThread.start();
// Send client data to core
String clientDate = new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.US).format(new Date());
......@@ -329,6 +332,8 @@ public class CoreConnection {
Heartbeat heartbeat = new Heartbeat();
busProvider.dispatch(heartbeat);
Log.d("libquassel", "Sending heartbeat");
Thread.sleep(30 * 1000);
}
} catch (InterruptedException e) {
......
......@@ -8,24 +8,22 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
import android.support.annotation.NonNull;
import de.kuschku.libquassel.client.QClient;
import de.kuschku.libquassel.functions.types.Heartbeat;
import de.kuschku.libquassel.functions.types.HeartbeatReply;
import de.kuschku.libquassel.functions.types.InitDataFunction;
......@@ -62,5 +60,5 @@ public interface IProtocolHandler {
void onEventMainThread(HeartbeatReply message);
@NonNull
Client getClient();
QClient getClient();
}
......@@ -8,32 +8,30 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
import android.support.annotation.NonNull;
import android.util.Log;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import de.kuschku.libquassel.client.QClient;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.CoreSetupRequiredEvent;
import de.kuschku.libquassel.events.GeneralErrorEvent;
import de.kuschku.libquassel.events.HandshakeFailedEvent;
import de.kuschku.libquassel.events.LoginFailedEvent;
import de.kuschku.libquassel.events.LoginSuccessfulEvent;
import de.kuschku.libquassel.events.LoginRequireEvent;
import de.kuschku.libquassel.functions.types.Heartbeat;
import de.kuschku.libquassel.functions.types.HeartbeatReply;
import de.kuschku.libquassel.functions.types.InitDataFunction;
......@@ -45,60 +43,45 @@ import de.kuschku.libquassel.objects.types.ClientInitReject;
import de.kuschku.libquassel.objects.types.ClientLoginAck;
import de.kuschku.libquassel.objects.types.ClientLoginReject;
import de.kuschku.libquassel.objects.types.SessionInit;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.syncables.SyncableRegistry;
import de.kuschku.libquassel.syncables.types.Identity;
import de.kuschku.libquassel.syncables.types.SyncableObject;
import de.kuschku.util.AndroidAssert;
import de.kuschku.util.ReflectionUtils;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class ProtocolHandler implements IProtocolHandler {
@NonNull
public final Client client;
public final QClient client;
@NonNull
private final BusProvider busProvider;
public ProtocolHandler(@NonNull BusProvider busProvider) {
public ProtocolHandler(@NonNull BusProvider busProvider, @NonNull QClient client) {
this.busProvider = busProvider;
this.busProvider.handle.register(this);
this.busProvider.event.register(this);
this.client = new Client(busProvider);
this.client = client;
}
public void onEventMainThread(@NonNull InitDataFunction packedFunc) {
try {
if (client.getConnectionStatus() == ConnectionChangeEvent.Status.CONNECTED) {
if (!packedFunc.className.equals("IrcUser"))
Log.e("libquassel", "Late Receive! " + packedFunc.toString());
} else {
if (client.getInitDataQueue().contains(packedFunc.className + ":" + packedFunc.objectName)) {
client.getInitDataQueue().remove(packedFunc.className + ":" + packedFunc.objectName);
if (client.getInitDataQueue().isEmpty()) {
client.setConnectionStatus(ConnectionChangeEvent.Status.CONNECTED);
busProvider.dispatch(new Heartbeat());
}
}
}
SyncableObject object = SyncableRegistry.from(packedFunc);
assertNotNull(object);
object.init(packedFunc, busProvider, client);
client.initObject(packedFunc.className, packedFunc.objectName, object);
} catch (Exception e) {
busProvider.sendEvent(new GeneralErrorEvent(e));
}
}
public void onEventMainThread(InitRequestFunction packedFunc) {
public void onEventMainThread(@NonNull InitRequestFunction packedFunc) {
}
public void onEventMainThread(@NonNull RpcCallFunction packedFunc) {
try {
if (packedFunc.functionName.substring(0, 1).equals("2")) {
ReflectionUtils.invokeMethod(client, packedFunc.functionName.substring(1), packedFunc.params);
ReflectionUtils.invokeMethod(client, "_" + packedFunc.functionName.substring(1), packedFunc.params);
} else if (packedFunc.functionName.equals("__objectRenamed__")) {
ReflectionUtils.invokeMethod(client, packedFunc.functionName, packedFunc.params);
ReflectionUtils.invokeMethod(client, "_" + packedFunc.functionName, packedFunc.params);
} else {
throw new IllegalArgumentException("Unknown type: " + packedFunc.functionName);
}
......@@ -109,14 +92,21 @@ public class ProtocolHandler implements IProtocolHandler {
public void onEventMainThread(@NonNull SyncFunction packedFunc) {
try {
final Object syncable = client.getObjectByIdentifier(packedFunc.className, packedFunc.objectName);
AndroidAssert.assertNotNull("Object not found: " + packedFunc.className + ":" + packedFunc.objectName, syncable);
ReflectionUtils.invokeMethod(syncable, packedFunc.methodName, packedFunc.params);
final Object syncable = client.unsafe_getObjectByIdentifier(packedFunc.className, packedFunc.objectName);
if (syncable == null) {
client.bufferSync(packedFunc);
} else {
if (syncable instanceof SyncableObject && !((SyncableObject) syncable).initialized()) {
client.initObject(packedFunc.className, packedFunc.objectName, (SyncableObject) syncable);
} else {
ReflectionUtils.invokeMethod(syncable, "_" + packedFunc.methodName, packedFunc.params);
}
}
} catch (Exception e) {
busProvider.sendEvent(new GeneralErrorEvent(e, packedFunc.toString()));
} catch (Error e) {
e.printStackTrace();
Log.e("EVENT", packedFunc.toString());
}
}
......@@ -127,65 +117,47 @@ public class ProtocolHandler implements IProtocolHandler {
public void onEvent(ClientInitAck message) {
client.setCore(message);
if (client.getCore().Configured) {
if (client.core().Configured) {
// Send an event to notify that login is necessary
client.setConnectionStatus(ConnectionChangeEvent.Status.LOGIN_REQUIRED);
busProvider.sendEvent(new LoginRequireEvent(false));
} else {
// Send an event to notify that the core is not yet set up
client.setConnectionStatus(ConnectionChangeEvent.Status.CORE_SETUP_REQUIRED);
busProvider.sendEvent(new CoreSetupRequiredEvent());
}
}
public void onEvent(ClientLoginAck message) {
busProvider.sendEvent(new LoginSuccessfulEvent());
client.setConnectionStatus(ConnectionChangeEvent.Status.CONNECTING);
}
public void onEvent(@NonNull ClientLoginReject message) {
busProvider.sendEvent(new LoginFailedEvent(message.Error));
busProvider.sendEvent(new LoginRequireEvent(true));
}
public void onEvent(@NonNull SessionInit message) {
busProvider.dispatch(new Heartbeat());
client.setState(message.SessionState);
client.setConnectionStatus(ConnectionChangeEvent.Status.INITIALIZING_DATA);
client.sendInitRequest("BufferSyncer", "", true);
client.sendInitRequest("BufferViewManager", "", true);
client.sendInitRequest("AliasManager", "", true);
client.sendInitRequest("NetworkConfig", "GlobalNetworkConfig", true);
client.sendInitRequest("IgnoreListManager", "", true);
//sendInitRequest("TransferManager", ""); // This thing never gets sent...
assertNotNull(client.getState());
for (int NetworkId : client.getState().NetworkIds) {
client.sendInitRequest("Network", String.valueOf(NetworkId), true);
}
for (Identity identity : client.getState().Identities) {
identity.init(null, busProvider, client);
}
for (BufferInfo info : message.SessionState.BufferInfos) {
final int initialBacklogCount = 10;
client.getBacklogManager().requestBacklog(info.id, -1, -1, initialBacklogCount, 0);
}
client.init(message.SessionState);
}
public void onEvent(@NonNull Heartbeat heartbeat) {
busProvider.dispatch(new HeartbeatReply(heartbeat.dateTime));
busProvider.dispatch(new HeartbeatReply(heartbeat));
}
public void onEventMainThread(@NonNull HeartbeatReply heartbeat) {
long roundtrip = DateTime.now().getMillis() - heartbeat.dateTime.getMillis();
DateTime dateTime = DateTime.now().toDateTimeISO();
Interval interval = new Interval(heartbeat.dateTime, dateTime);
long roundtrip = interval.toDurationMillis();
long lag = (long) (roundtrip * 0.5);
client.setLag(lag);
client.setLatency(lag);
}
public void onEvent(@NonNull ConnectionChangeEvent event) {
}
@NonNull
@Override
public Client getClient() {
public QClient getClient() {
return client;
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
import android.support.annotation.NonNull;
import de.kuschku.libquassel.client.ClientData;
import de.kuschku.libquassel.client.QClient;
import de.kuschku.libquassel.localtypes.backlogstorage.BacklogStorage;
import de.kuschku.libquassel.ssl.CertificateManager;
import de.kuschku.util.ServerAddress;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class QuasselClient {
@NonNull
public final BusProvider provider;
@NonNull
public final ProtocolHandler handler;
@NonNull
public final QClient client;
@NonNull
public final CertificateManager certificateManager;
@NonNull
private final ClientData data;
public CoreConnection connection;
public QuasselClient(@NonNull BusProvider provider, @NonNull ClientData data, @NonNull CertificateManager certificateManager, @NonNull BacklogStorage backlogStorage) {
assertNotNull(provider);
assertNotNull(data);
assertNotNull(certificateManager);
assertNotNull(backlogStorage);
this.provider = provider;
this.data = data;
this.certificateManager = certificateManager;
this.client = new QClient(provider, backlogStorage);
this.handler = new ProtocolHandler(provider, this.client);
}
public void connect(@NonNull ServerAddress address) {
assertNotNull(client);
this.connection = new CoreConnection(address, data, provider, client, certificateManager);
}
public void disconnect() {
this.connection.close();
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.functions.types.HandshakeFunction;
import de.kuschku.libquassel.objects.types.ClientLogin;
import de.kuschku.libquassel.objects.types.Command;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.types.SyncableObject;
import de.kuschku.libquassel.syncables.types.impl.NetworkInfo;
import de.kuschku.libquassel.syncables.types.interfaces.QIdentity;
import static de.kuschku.util.AndroidAssert.fail;
import static junit.framework.Assert.assertNotNull;
public abstract class AClient<T extends AClient<T>> extends SyncableObject<T> implements QClientInterface {
@Override
public void sendInput(BufferInfo info, String message) {
smartRpc("sendInput(BufferInfo, QString)", info, message);
}
@Override
public void sendInput(@NonNull Command command) {
sendInput(command.buffer, command.command);
}
@Override
public void createIdentity(QIdentity identity) {
smartRpc("createIdentity(Identity,QVariantMap)", identity);
}
@Override
public void updateIdentity(int id, Map<String, QVariant> serialized) {
smartRpc("updateIdenity(IdentityId,QVariantMap)", id, serialized);
}
@Override
public void removeIdentity(int id) {
smartRpc("removeIdentity(IdentityId)", id);
}
@Override
public void createNetwork(NetworkInfo info) {
createNetwork(info, new ArrayList<>(0));
}
@Override
public void createNetwork(NetworkInfo info, List<String> persistentChannels) {
smartRpc("createNetwork(NetworkInfo,QStringList)", info, persistentChannels);
}
@Override
public void updateNetwork(NetworkInfo info) {
smartRpc("updateNetwork(NetworkInfo)", info);
}
@Override
public void removeNetwork(int id) {
smartRpc("2removeNetwork(NetworkId)", id);
}
@Override
public void changePassword(String username, String oldPassword, String newPassword) {
smartRpc("changePassword(PeerPtr,QString,QString,QString)", 0x0000000000000000L, username, oldPassword, newPassword);
}
@Override
public void update(T from) {
fail("This is not a real syncable");
}
@Override
public void update(Map<String, QVariant> from) {
fail("This is not a real syncable");
}
@Override
public void login(@NonNull String username, @NonNull String password) {
assertNotNull(provider);
provider.dispatch(new HandshakeFunction(new ClientLogin(username, password)));
}
}
......@@ -8,21 +8,18 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel;
package de.kuschku.libquassel.client;
import android.support.annotation.NonNull;
......@@ -75,31 +72,4 @@ public class ClientData {
'}';
}
public static class FeatureFlags {
public final boolean supportsSSL;
public final boolean supportsCompression;
public final byte flags;
public FeatureFlags(final byte flags) {
this.flags = flags;
this.supportsSSL = (flags & 0x01) > 0;
this.supportsCompression = (flags & 0x02) > 0;
}
public FeatureFlags(final boolean supportsSSL, final boolean supportsCompression) {
this.supportsSSL = supportsSSL;
this.supportsCompression = supportsCompression;
this.flags = (byte) ((this.supportsSSL ? 0x01 : 0x00) |
(this.supportsCompression ? 0x02 : 0x00));
}
@NonNull
@Override
public String toString() {
return "FeatureFlags{" +
"supportsSSL=" + supportsSSL +
", supportsCompression=" + supportsCompression +
'}';
}
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import android.support.annotation.NonNull;
public class FeatureFlags {
public final boolean supportsSSL;
public final boolean supportsCompression;
public final byte flags;
public FeatureFlags(final byte flags) {
this.flags = flags;
this.supportsSSL = (flags & 0x01) > 0;
this.supportsCompression = (flags & 0x02) > 0;
}
public FeatureFlags(final boolean supportsSSL, final boolean supportsCompression) {
this.supportsSSL = supportsSSL;
this.supportsCompression = supportsCompression;
this.flags = (byte) ((this.supportsSSL ? 0x01 : 0x00) |
(this.supportsCompression ? 0x02 : 0x00));
}
@NonNull
@Override
public String toString() {
return "FeatureFlags{" +
"supportsSSL=" + supportsSSL +
", supportsCompression=" + supportsCompression +
'}';
}
}
......@@ -8,70 +8,75 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.syncables.types;
package de.kuschku.libquassel.client;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.serializers.BufferViewManagerSerializer;
import de.kuschku.libquassel.localtypes.buffers.Buffer;
import de.kuschku.libquassel.localtypes.buffers.Buffers;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
public class BufferViewManager extends SyncableObject<BufferViewManager> {
public class QBufferManager {
@NonNull
public Map<Integer, BufferViewConfig> BufferViews = new HashMap<>();
private Client client;
private final Map<Integer, Buffer> buffers = new HashMap<>();
private final QClient client;
public BufferViewManager(@NonNull List<Integer> BufferViewIds) {
for (int i : BufferViewIds) {
BufferViews.put(i, null);
// We cache those, because the networks might not be initialized at begin
@Nullable
private List<BufferInfo> bufferInfos;
public QBufferManager(QClient client) {
this.client = client;
}
public void createBuffer(@NonNull Buffer buffer) {
buffers.put(buffer.getInfo().id(), buffer);
}
@NonNull
@Override
public String toString() {
return "BufferViewManager{" +
"BufferViews=" + BufferViews +
'}';
public void removeBuffer(@IntRange(from = 0) int id) {
buffers.remove(id);
}
@Override
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
this.client = client;
setObjectName(function.objectName);
client.setBufferViewManager(this);
public Buffer buffer(@IntRange(from = 0) int id) {
return buffers.get(id);
}
@Override
public void update(@NonNull BufferViewManager from) {
this.BufferViews = from.BufferViews;
for (int id : BufferViews.keySet()) {
client.sendInitRequest("BufferViewConfig", String.valueOf(id));
public void updateBufferInfo(@NonNull BufferInfo bufferInfo) {
Buffer buffer = buffer(bufferInfo.id());
if (buffer == null) return;
buffer.setInfo(bufferInfo);
}
public void init(List<BufferInfo> bufferInfos) {
this.bufferInfos = bufferInfos;
}
@Override
public void update(@NonNull Map<String, QVariant> from) {
update(BufferViewManagerSerializer.get().fromDatastream(from));
public void postInit() {
for (BufferInfo info : bufferInfos) {
QNetwork network = client.networkManager().network(info.networkId());
if (network == null) continue;
Buffer buffer = Buffers.fromType(info, network);
if (buffer == null) continue;
createBuffer(buffer);
}
bufferInfos = null;
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.CriticalErrorEvent;
import de.kuschku.libquassel.events.LagChangedEvent;
import de.kuschku.libquassel.events.PasswordChangeEvent;
import de.kuschku.libquassel.events.StatusMessageEvent;
import de.kuschku.libquassel.functions.types.InitRequestFunction;
import de.kuschku.libquassel.functions.types.SyncFunction;
import de.kuschku.libquassel.localtypes.NotificationManager;
import de.kuschku.libquassel.localtypes.backlogstorage.BacklogStorage;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.objects.types.CoreStatus;
import de.kuschku.libquassel.objects.types.SessionState;
import de.kuschku.libquassel.primitives.QMetaTypeRegistry;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.syncables.types.SyncableObject;
import de.kuschku.libquassel.syncables.types.impl.AliasManager;
import de.kuschku.libquassel.syncables.types.impl.BacklogManager;
import de.kuschku.libquassel.syncables.types.impl.BufferSyncer;
import de.kuschku.libquassel.syncables.types.impl.BufferViewManager;
import de.kuschku.libquassel.syncables.types.impl.CoreInfo;
import de.kuschku.libquassel.syncables.types.impl.Identity;
import de.kuschku.libquassel.syncables.types.impl.IgnoreListManager;
import de.kuschku.libquassel.syncables.types.impl.NetworkConfig;
import de.kuschku.libquassel.syncables.types.interfaces.QAliasManager;
import de.kuschku.libquassel.syncables.types.interfaces.QBacklogManager;
import de.kuschku.libquassel.syncables.types.interfaces.QBufferSyncer;
import de.kuschku.libquassel.syncables.types.interfaces.QBufferViewManager;
import de.kuschku.libquassel.syncables.types.interfaces.QIgnoreListManager;
import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
import de.kuschku.libquassel.syncables.types.interfaces.QNetworkConfig;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class QClient extends AClient {
// synced
@NonNull
private final QNetworkManager networkManager;
@NonNull
private final QBufferManager bufferManager;
@NonNull
private final QIdentityManager identityManager;
@NonNull
private final BacklogStorage backlogStorage;
@NonNull
private final NotificationManager notificationManager;
private final List<String> initRequests = new LinkedList<>();
private final List<Integer> backlogRequests = new LinkedList<>();
private final Map<String, SyncFunction> bufferedSyncs = new HashMap<>();
private final QBacklogManager backlogManager;
private QBufferViewManager bufferViewManager;
// local
private QBufferSyncer bufferSyncer;
private QAliasManager aliasManager;
private QIgnoreListManager ignoreListManager;
private QNetworkConfig globalNetworkConfig;
private CoreStatus core;
private CoreInfo coreInfo;
private long latency;
private ConnectionChangeEvent.Status connectionStatus;
public QClient(@NonNull BusProvider provider, @NonNull BacklogStorage backlogStorage) {
this.provider = provider;
this.networkManager = new QNetworkManager(this);
this.bufferManager = new QBufferManager(this);
this.identityManager = new QIdentityManager(this);
this.backlogStorage = backlogStorage;
backlogStorage.setClient(this);
this.backlogManager = new BacklogManager(this, backlogStorage);
this.notificationManager = new NotificationManager(this);
}
public QBufferViewManager bufferViewManager() {
return bufferViewManager;
}
public QBufferSyncer bufferSyncer() {
return bufferSyncer;
}
public QAliasManager aliasManager() {
return aliasManager;
}
public QBacklogManager backlogManager() {
return backlogManager;
}
public QIgnoreListManager ignoreListManager() {
return ignoreListManager;
}
public QNetworkConfig globalNetworkConfig() {
return globalNetworkConfig;
}
@Override
public void _displayMsg(Message msg) {
backlogStorage.insertMessages(msg);
}
@Override
public void _displayStatusMsg(String network, String message) {
provider.sendEvent(new StatusMessageEvent(network, message));
}
@Override
public void _bufferInfoUpdated(BufferInfo bufferInfo) {
bufferManager.updateBufferInfo(bufferInfo);
}
@Override
public void _identityCreated(Identity identity) {
identityManager.createIdentity(identity);
}
@Override
public void _identityRemoved(int id) {
identityManager.removeIdentity(id);
}
@Override
public void _networkCreated(int network) {
networkManager.createNetwork(network);
}
@Override
public void _networkRemoved(int network) {
networkManager.removeNetwork(network);
}
@Override
public void _passwordChanged(long peerPtr, boolean success) {
if (peerPtr != 0x0000000000000000L)
provider.sendEvent(new CriticalErrorEvent("Your core has a critical vulnerability. Please update it."));
provider.sendEvent(new PasswordChangeEvent(success));
}
@Override
public void ___objectRenamed__(String type, String oldName, String newName) {
}
public ConnectionChangeEvent.Status connectionStatus() {
return connectionStatus;
}
public void setConnectionStatus(@NonNull ConnectionChangeEvent.Status connectionStatus) {
assertNotNull(provider);
this.connectionStatus = connectionStatus;
switch (connectionStatus) {
case LOADING_BACKLOG: {
bufferManager.postInit();
networkManager.postInit();
setConnectionStatus(ConnectionChangeEvent.Status.CONNECTED);
}
break;
}
provider.sendEvent(new ConnectionChangeEvent(connectionStatus));
}
@Nullable
public Object unsafe_getObjectByIdentifier(@NonNull String className, @NonNull String objectName) {
switch (className) {
case "AliasManager": {
assertNotNull(aliasManager);
return aliasManager;
}
case "BacklogManager": {
assertNotNull(backlogManager);
return backlogManager;
}
case "BufferSyncer": {
assertNotNull(bufferSyncer);
return bufferSyncer;
}
case "BufferViewConfig": {
assertNotNull(bufferViewManager);
return bufferViewManager.bufferViewConfig(Integer.parseInt(objectName));
}
case "BufferViewManager": {
assertNotNull(bufferViewManager);
return bufferViewManager;
}
case "CoreInfo": {
assertNotNull(coreInfo);
return coreInfo;
}
case "Identity": {
return identityManager.identity(Integer.parseInt(objectName));
}
case "IgnoreListManager": {
assertNotNull(ignoreListManager);
return ignoreListManager;
}
case "IrcChannel": {
String[] split = objectName.split("/");
if (split.length != 2) {
Log.w("libquassel", "malformatted object name: " + objectName);
return null;
}
QNetwork network = networkManager.network(Integer.parseInt(split[0]));
if (network == null) {
Log.w("libquassel", "Network doesn’t exist yet: " + objectName);
return null;
}
return network.ircChannel(split[1]);
}
case "IrcUser": {
String[] split = objectName.split("/");
if (split.length != 2) {
Log.w("libquassel", "malformatted object name: " + objectName);
return null;
}
QNetwork network = networkManager.network(Integer.parseInt(split[0]));
if (network == null) {
Log.w("libquassel", "Network doesn’t exist yet: " + objectName);
return null;
}
return network.ircUser(split[1]);
}
case "Network": {
return networkManager.network(Integer.parseInt(objectName));
}
case "NetworkConfig": {
assertNotNull(globalNetworkConfig);
return globalNetworkConfig;
}
case "NetworkInfo": {
return getObjectByIdentifier(QNetwork.class, "Network", objectName).networkInfo();
}
default: {
Log.w("libquassel", "Unknown type: " + className + " : " + objectName);
return null;
}
}
}
@Nullable
public <T> T getObjectByIdentifier(@NonNull String className, @NonNull String objectName) {
Class<T> cl = QMetaTypeRegistry.<T>getType(className).cl;
return getObjectByIdentifier(cl, className, objectName);
}
@Nullable
public <T> T getObjectByIdentifier(@NonNull Class<T> cl, @NonNull String objectName) {
return getObjectByIdentifier(cl, cl.getSimpleName(), objectName);
}
@SuppressWarnings("unchecked")
@Nullable
public <T> T getObjectByIdentifier(@NonNull Class<T> cl, @NonNull String className, @NonNull String objectName) {
Object obj = unsafe_getObjectByIdentifier(className, objectName);
// The fancy version of "instanceof" that works with erased types, too
if (obj == null || !cl.isAssignableFrom(obj.getClass()))
return null;
else
return (T) obj;
}
public void init(@NonNull SessionState sessionState) {
networkManager.init(sessionState.NetworkIds);
identityManager.init(sessionState.Identities);
bufferManager.init(sessionState.BufferInfos);
requestInitObject("BufferSyncer", "");
requestInitObject("BufferViewManager", "");
requestInitObject("AliasManager", "");
requestInitObject("NetworkConfig", "GlobalNetworkConfig");
requestInitObject("IgnoreListManager", "");
//sendInitRequest("TransferManager", "");
// This thing never gets sent...
}
@NonNull
public QNetworkManager networkManager() {
return networkManager;
}
@NonNull
public QBufferManager bufferManager() {
return bufferManager;
}
@NonNull
public QIdentityManager identityManager() {
return identityManager;
}
public void requestInitObject(@NonNull String className, String objectName) {
assertNotNull(provider);
if (connectionStatus() == ConnectionChangeEvent.Status.INITIALIZING_DATA)
initRequests.add(hashName(className, objectName));
provider.dispatch(new InitRequestFunction(className, objectName));
}
public void initObject(String className, @NonNull String objectName, @NonNull SyncableObject object) {
assertNotNull(provider);
if (connectionStatus() == ConnectionChangeEvent.Status.INITIALIZING_DATA) {
initRequests.remove(hashName(className, objectName));
if (initRequests.isEmpty()) {
setConnectionStatus(ConnectionChangeEvent.Status.LOADING_BACKLOG);
}
}
object.init(objectName, provider, this);
// Execute cached sync requests
if (bufferedSyncs.size() > 0) {
String key = hashName(className, objectName);
if (bufferedSyncs.containsKey(key)) {
provider.handle(bufferedSyncs.get(key));
}
}
}
@NonNull
private String hashName(String className, String objectName) {
return className + ":" + objectName;
}
public void initBacklog(int id) {
backlogRequests.remove((Integer) id);
requestInitBacklog(id, 0);
if (backlogRequests.isEmpty())
setConnectionStatus(ConnectionChangeEvent.Status.CONNECTED);
}
public void requestInitBacklog(int id, int amount) {
backlogRequests.add(id);
backlogManager.requestBacklogInitial(id, amount);
}
public void setLatency(long latency) {
assertNotNull(provider);
this.latency = latency;
provider.sendEvent(new LagChangedEvent(latency));
}
public CoreInfo coreInfo() {
return coreInfo;
}
public void setCoreInfo(CoreInfo coreInfo) {
this.coreInfo = coreInfo;
}
public CoreStatus core() {
return core;
}
public void setCore(CoreStatus core) {
this.core = core;
}
public long latency() {
return latency;
}
@NonNull
public NotificationManager notificationManager() {
return notificationManager;
}
public void setBufferSyncer(BufferSyncer bufferSyncer) {
this.bufferSyncer = bufferSyncer;
}
public void setBufferViewManager(BufferViewManager bufferViewManager) {
this.bufferViewManager = bufferViewManager;
}
public void setAliasManager(AliasManager aliasManager) {
this.aliasManager = aliasManager;
}
public void setIgnoreListManager(IgnoreListManager ignoreListManager) {
this.ignoreListManager = ignoreListManager;
}
public void setGlobalNetworkConfig(NetworkConfig globalNetworkConfig) {
this.globalNetworkConfig = globalNetworkConfig;
}
@NonNull
public BacklogStorage backlogStorage() {
return backlogStorage;
}
public void bufferSync(@NonNull SyncFunction packedFunc) {
String key = hashName(packedFunc.className, packedFunc.objectName);
bufferedSyncs.put(key, packedFunc);
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.objects.types.Command;
import de.kuschku.libquassel.primitives.types.BufferInfo;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.Synced;
import de.kuschku.libquassel.syncables.types.impl.Identity;
import de.kuschku.libquassel.syncables.types.impl.NetworkInfo;
import de.kuschku.libquassel.syncables.types.interfaces.QIdentity;
public interface QClientInterface {
@Synced
void sendInput(BufferInfo info, String message);
@Synced
void sendInput(Command command);
@Synced
void createIdentity(QIdentity identity);
@Synced
void updateIdentity(int id, final Map<String, QVariant> serialized);
@Synced
void removeIdentity(int id);
@Synced
void createNetwork(NetworkInfo info);
@Synced
void createNetwork(NetworkInfo info, List<String> persistentChannels);
@Synced
void updateNetwork(NetworkInfo info);
@Synced
void removeNetwork(int id);
@Synced
void changePassword(String username, String oldPassword, String newPassword);
void _displayMsg(final Message msg);
void _displayStatusMsg(String network, String message);
void _bufferInfoUpdated(BufferInfo bufferInfo);
void _identityCreated(Identity identity);
void _identityRemoved(int id);
void _networkCreated(int network);
void _networkRemoved(int network);
void _passwordChanged(long peerPtr, boolean success);
void ___objectRenamed__(String type, String oldName, String newName);
void login(String username, String password);
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.syncables.types.interfaces.QIdentity;
public class QIdentityManager {
@NonNull
private final Map<Integer, QIdentity> identities = new HashMap<>();
private final QClient client;
public QIdentityManager(QClient client) {
this.client = client;
}
public void createIdentity(@NonNull QIdentity identity) {
identities.put(identity.id(), identity);
}
public void removeIdentity(@IntRange(from = 0) int id) {
identities.remove(id);
}
public QIdentity identity(@IntRange(from = 0) int id) {
return identities.get(id);
}
public void init(@NonNull List<QIdentity> identities) {
for (QIdentity identity : identities) {
createIdentity(identity);
}
}
}
/*
* QuasselDroid - Quassel client for Android
* Copyright (C) 2016 Janne Koschinski
* Copyright (C) 2016 Ken Børge Viktil
* Copyright (C) 2016 Magnus Fjell
* Copyright (C) 2016 Martin Sandsmark <martin.sandsmark@kde.org>
*
* 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)
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.client;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.syncables.types.impl.Network;
import de.kuschku.libquassel.syncables.types.interfaces.QNetwork;
public class QNetworkManager {
@NonNull
private final Map<Integer, QNetwork> networks = new HashMap<>();
private final QClient client;
public QNetworkManager(QClient client) {
this.client = client;
}
public void createNetwork(@IntRange(from = 0) int networkId) {
createNetwork(Network.create(networkId));
}
public void createNetwork(@NonNull QNetwork network) {
networks.put(network.networkId(), network);
}
public QNetwork network(@IntRange(from = 0) int networkId) {
return networks.get(networkId);
}
public void removeNetwork(@IntRange(from = 0) int network) {
networks.remove(network);
}
public void init(@NonNull List<Integer> networkIds) {
for (int networkId : networkIds) {
createNetwork(networkId);
client.requestInitObject("Network", String.valueOf(networkId));
}
}
public void onDone(Runnable runnable) {
}
public void postInit() {
for (QNetwork network : networks.values()) {
network.postInit();
}
}
}
......@@ -8,18 +8,15 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.events;
......
......@@ -8,18 +8,15 @@
* 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)
* any later version, or under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
* any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License and the
* GNU Lesser General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.kuschku.libquassel.events;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment