Add basic MCS implementation to realize C2DM (used by GCM)

- Can be started using `am startservice com.google.android.gms/org.microg.gms.gcm.mcs.McsService` on device
- Does not send Heartbeats -> Connection will be closed after 30 minutes
- No automatic reconnect on connection closure
- Only push, no bidirectional communication
This commit is contained in:
mar-v-in 2015-03-22 14:32:51 +01:00
parent b150e73332
commit 93c3cbb31b
21 changed files with 2935 additions and 0 deletions

View File

@ -0,0 +1,28 @@
/*
* Copyright 2013-2015 µg Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.gcm.mcs;
public class Constants {
public static final int MCS_HEARTBEAT_ACK_TAG = 1;
public static final int MCS_LOGIN_REQUEST_TAG = 2;
public static final int MCS_LOGIN_RESPONSE_TAG = 3;
public static final int MCS_CLOSE_TAG = 4;
public static final int MCS_IQ_STANZA_TAG = 7;
public static final int MCS_DATA_MESSAGE_STANZA_TAG = 8;
public static final int MCS_VERSION_CODE = 41;
}

View File

@ -0,0 +1,127 @@
/*
* Copyright 2013-2015 µg Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.gcm.mcs;
import android.util.Base64;
import android.util.Log;
import com.squareup.wire.Message;
import com.squareup.wire.Wire;
import java.io.IOException;
import java.io.InputStream;
import static org.microg.gms.gcm.mcs.Constants.MCS_CLOSE_TAG;
import static org.microg.gms.gcm.mcs.Constants.MCS_DATA_MESSAGE_STANZA_TAG;
import static org.microg.gms.gcm.mcs.Constants.MCS_HEARTBEAT_ACK_TAG;
import static org.microg.gms.gcm.mcs.Constants.MCS_IQ_STANZA_TAG;
import static org.microg.gms.gcm.mcs.Constants.MCS_LOGIN_REQUEST_TAG;
import static org.microg.gms.gcm.mcs.Constants.MCS_LOGIN_RESPONSE_TAG;
public class McsInputStream {
private static final String TAG = "GmsGcmMcsInput";
private final InputStream is;
private boolean initialized;
private int version = -1;
private int lastStreamIdReported = -1;
private int streamId = 0;
public McsInputStream(InputStream is) {
this(is, false);
}
public McsInputStream(InputStream is, boolean initialized) {
this.is = is;
this.initialized = initialized;
}
public int getStreamId() {
lastStreamIdReported = streamId;
return streamId;
}
public boolean newStreamIdAvailable() {
return lastStreamIdReported != streamId;
}
public int getVersion() {
ensureVersionRead();
return version;
}
private void ensureVersionRead() {
if (!initialized) {
try {
version = is.read();
Log.d(TAG, "Reading from MCS version=" + version);
initialized = true;
} catch (IOException e) {
Log.w(TAG, e);
}
}
}
public synchronized Message read() throws IOException {
ensureVersionRead();
int mcsTag = is.read();
int mcsSize = readVarint();
Log.d(TAG, "Reading from MCS tag=" + mcsTag + " size=" + mcsSize);
byte[] bytes = new byte[mcsSize];
int len = 0;
while ((len += is.read(bytes, len, mcsSize - len)) < mcsSize) ;
Log.d(TAG, "Reading from MCS: " + Base64.encodeToString(bytes, 0));
Message read = read(mcsTag, bytes, len);
Log.d(TAG, "Read from MCS: " + read);
streamId++;
return read;
}
private static Message read(int mcsTag, byte[] bytes, int len) throws IOException {
Wire wire = new Wire();
switch (mcsTag) {
case MCS_HEARTBEAT_ACK_TAG:
return wire.parseFrom(bytes, 0, len, HeartbeatAck.class);
case MCS_LOGIN_REQUEST_TAG:
return wire.parseFrom(bytes, 0, len, LoginRequest.class);
case MCS_LOGIN_RESPONSE_TAG:
return wire.parseFrom(bytes, 0, len, LoginResponse.class);
case MCS_CLOSE_TAG:
return wire.parseFrom(bytes, 0, len, Close.class);
case MCS_IQ_STANZA_TAG:
return wire.parseFrom(bytes, 0, len, IqStanza.class);
case MCS_DATA_MESSAGE_STANZA_TAG:
return wire.parseFrom(bytes, 0, len, DataMessageStanza.class);
default:
return null;
}
}
private int readVarint() throws IOException {
int res = 0;
int s = 0;
int b = 0x80;
while ((b & 0x80) == 0x80) {
b = is.read();
res |= (b & 0x7F) << s;
s += 7;
}
return res;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2013-2015 µg Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.gcm.mcs;
import android.util.Log;
import com.squareup.wire.Message;
import java.io.IOException;
import java.io.OutputStream;
import static org.microg.gms.gcm.mcs.Constants.*;
public class McsOutputStream {
private static final String TAG = "GmsGcmMcsOutput";
private final OutputStream os;
private boolean initialized;
private int version = MCS_VERSION_CODE;
private int streamId = 0;
public McsOutputStream(OutputStream os) {
this(os, false);
}
public McsOutputStream(OutputStream os, boolean initialized) {
this.os = os;
this.initialized = initialized;
}
public int getStreamId() {
return streamId;
}
public void write(DataMessageStanza message) throws IOException {
write(message, MCS_DATA_MESSAGE_STANZA_TAG);
}
public void write(LoginRequest loginRequest) throws IOException {
write(loginRequest, MCS_LOGIN_REQUEST_TAG);
}
public void write(HeartbeatAck ack) throws IOException {
write(ack, MCS_HEARTBEAT_ACK_TAG);
}
public synchronized void write(Message message, int tag) throws IOException {
if (!initialized) {
Log.d(TAG, "Write MCS version code: " + version);
os.write(version);
initialized = true;
}
Log.d(TAG, "Write to MCS: " + message);
os.write(tag);
writeVarint(os, message.getSerializedSize());
os.write(message.toByteArray());
os.flush();
streamId++;
}
private void writeVarint(OutputStream os, int value) throws IOException {
while (true) {
if ((value & ~0x7FL) == 0) {
os.write(value);
return;
} else {
os.write((value & 0x7F) | 0x80);
value >>>= 7;
}
}
}
}

View File

@ -0,0 +1,196 @@
/*
* Copyright 2013-2015 µg Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.microg.gms.gcm.mcs;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import com.squareup.wire.Message;
import org.microg.gms.checkin.LastCheckinInfo;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLContext;
import static android.os.Build.VERSION.SDK_INT;
public class McsService extends IntentService {
private static final String TAG = "GmsGcmMcsSvc";
public static final String PREFERENCES_NAME = "mcs";
public static final String SERVICE_HOST = "mtalk.google.com";
public static final int SERVICE_PORT = 5228;
public static final String PREF_LAST_PERSISTENT_ID = "last_persistent_id";
public static final String SELF_CATEGORY = "com.google.android.gsf.gtalkservice";
public static final String IDLE_NOTIFICATION = "IdleNotification";
public static final String FROM_FIELD = "gcm@android.com";
private static AtomicBoolean connected = new AtomicBoolean(false);
private Socket socket;
private Socket sslSocket;
private McsInputStream inputStream;
private McsOutputStream outputStream;
public McsService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
if (connected.compareAndSet(false, true)) {
new Thread(new Runnable() {
@Override
public void run() {
connect();
}
}).start();
} else {
Log.d(TAG, "MCS connection already started");
}
}
private void connect() {
try {
Log.d(TAG, "Starting MCS connection...");
LastCheckinInfo info = LastCheckinInfo.read(this);
socket = new Socket(SERVICE_HOST, SERVICE_PORT);
Log.d(TAG, "Connected to " + SERVICE_HOST + ":" + SERVICE_PORT);
sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, "mtalk.google.com", 5228, true);
Log.d(TAG, "Activated SSL with " + SERVICE_HOST + ":" + SERVICE_PORT);
inputStream = new McsInputStream(sslSocket.getInputStream());
outputStream = new McsOutputStream(sslSocket.getOutputStream());
LoginRequest loginRequest = buildLoginRequest(info);
Log.d(TAG, "Sending login request...");
outputStream.write(loginRequest);
boolean close = false;
while (!close) {
Message o = inputStream.read();
if (o instanceof DataMessageStanza) {
handleMessage((DataMessageStanza) o);
} else if (o instanceof HeartbeatPing) {
handleHearbeatPing((HeartbeatPing) o);
} else if (o instanceof Close) {
handleClose((Close) o);
} else if (o instanceof LoginResponse) {
handleLoginresponse((LoginResponse) o);
}
}
socket.close();
} catch (Exception e) {
Log.w(TAG, e);
try {
sslSocket.close();
} catch (Exception ignored) {
}
}
connected.set(false);
}
private void handleClose(Close close) throws IOException {
throw new IOException("Server requested close!");
}
private void handleLoginresponse(LoginResponse loginResponse) throws IOException {
getSharedPreferences().edit().putString(PREF_LAST_PERSISTENT_ID, null);
if (loginResponse.error == null) {
Log.d(TAG, "Logged in");
} else {
throw new IOException("Could not login: " + loginResponse.error);
}
}
private void handleMessage(DataMessageStanza message) throws IOException {
if (message.persistent_id != null) {
String old = getSharedPreferences().getString(PREF_LAST_PERSISTENT_ID, null);
if (old == null) {
old = "";
} else {
old += "|";
}
getSharedPreferences().edit()
.putString(PREF_LAST_PERSISTENT_ID, old + message.persistent_id).apply();
}
if (SELF_CATEGORY.equals(message.category)) {
handleSelfMessage(message);
} else {
handleAppMessage(message);
}
}
private void handleHearbeatPing(HeartbeatPing ping) throws IOException {
HeartbeatAck.Builder ack = new HeartbeatAck.Builder().status(ping.status);
if (inputStream.newStreamIdAvailable()) {
ack.last_stream_id_received(inputStream.getStreamId());
}
outputStream.write(ack.build());
}
private LoginRequest buildLoginRequest(LastCheckinInfo info) {
return new LoginRequest.Builder()
.adaptive_heartbeat(false)
.auth_service(LoginRequest.AuthService.ANDROID_ID)
.auth_token(Long.toString(info.securityToken))
.id("android-" + SDK_INT)
.domain("mcs.android.com")
.device_id("android-" + Long.toHexString(info.androidId))
.network_type(1)
.resource(Long.toString(info.androidId))
.user(Long.toString(info.androidId))
.use_rmq2(true)
.setting(Arrays.asList(new Setting("new_vc", "1")))
.received_persistent_id(Arrays.asList(getSharedPreferences().getString(PREF_LAST_PERSISTENT_ID, "").split("\\|")))
.build();
}
private void handleAppMessage(DataMessageStanza msg) {
Intent intent = new Intent();
intent.setAction("com.google.android.c2dm.intent.RECEIVE");
intent.addCategory(msg.category);
for (AppData appData : msg.app_data) {
intent.putExtra(appData.key, appData.value);
}
sendOrderedBroadcast(intent, msg.category + ".permission.C2D_MESSAGE");
}
private void handleSelfMessage(DataMessageStanza msg) throws IOException {
for (AppData appData : msg.app_data) {
if (IDLE_NOTIFICATION.equals(appData.key)) {
DataMessageStanza.Builder msgResponse = new DataMessageStanza.Builder()
.from(FROM_FIELD)
.sent(System.currentTimeMillis() / 1000)
.ttl(0)
.category(SELF_CATEGORY)
.app_data(Arrays.asList(new AppData(IDLE_NOTIFICATION, "false")));
if (inputStream.newStreamIdAvailable()) {
msgResponse.last_stream_id_received(inputStream.getStreamId());
}
outputStream.write(msgResponse.build());
}
}
}
private SharedPreferences getSharedPreferences() {
return getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
}
}

View File

@ -0,0 +1,83 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
public final class AppData extends Message {
public static final String DEFAULT_KEY = "";
public static final String DEFAULT_VALUE = "";
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String key;
@ProtoField(tag = 2, type = STRING, label = REQUIRED)
public final String value;
public AppData(String key, String value) {
this.key = key;
this.value = value;
}
private AppData(Builder builder) {
this(builder.key, builder.value);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof AppData)) return false;
AppData o = (AppData) other;
return equals(key, o.key)
&& equals(value, o.value);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = key != null ? key.hashCode() : 0;
result = result * 37 + (value != null ? value.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<AppData> {
public String key;
public String value;
public Builder() {
}
public Builder(AppData message) {
super(message);
if (message == null) return;
this.key = message.key;
this.value = message.value;
}
public Builder key(String key) {
this.key = key;
return this;
}
public Builder value(String value) {
this.value = value;
return this;
}
@Override
public AppData build() {
checkRequiredFields();
return new AppData(this);
}
}
}

View File

@ -0,0 +1,43 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
/**
* TAG: 4
*/
public final class Close extends Message {
public Close() {
}
private Close(Builder builder) {
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
return other instanceof Close;
}
@Override
public int hashCode() {
return 0;
}
public static final class Builder extends Message.Builder<Close> {
public Builder() {
}
public Builder(Close message) {
super(message);
}
@Override
public Close build() {
return new Close(this);
}
}
}

View File

@ -0,0 +1,398 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;
import static com.squareup.wire.Message.Datatype.BOOL;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REPEATED;
import static com.squareup.wire.Message.Label.REQUIRED;
/**
* TAG: 8
*/
public final class DataMessageStanza extends Message {
public static final String DEFAULT_ID = "";
public static final String DEFAULT_FROM = "";
public static final String DEFAULT_TO = "";
public static final String DEFAULT_CATEGORY = "";
public static final String DEFAULT_TOKEN = "";
public static final List<AppData> DEFAULT_APP_DATA = Collections.emptyList();
public static final Boolean DEFAULT_FROM_TRUSTED_SERVER = false;
public static final String DEFAULT_PERSISTENT_ID = "";
public static final Integer DEFAULT_STREAM_ID = 0;
public static final Integer DEFAULT_LAST_STREAM_ID_RECEIVED = 0;
public static final String DEFAULT_REG_ID = "";
public static final Long DEFAULT_DEVICE_USER_ID = 0L;
public static final Integer DEFAULT_TTL = 0;
public static final Long DEFAULT_SENT = 0L;
public static final Integer DEFAULT_QUEUED = 0;
public static final Long DEFAULT_STATUS = 0L;
/**
* Not used.
* optional int64 rmq_id = 1;
* This is the message ID, set by client, DMP.9 (message_id)
*/
@ProtoField(tag = 2, type = STRING)
public final String id;
/**
* Project ID of the sender, DMP.1
*/
@ProtoField(tag = 3, type = STRING, label = REQUIRED)
public final String from;
/**
* Part of DMRequest - also the key in DataMessageProto.
*/
@ProtoField(tag = 4, type = STRING)
public final String to;
/**
* Package name. DMP.2
*/
@ProtoField(tag = 5, type = STRING, label = REQUIRED)
public final String category;
/**
* The collapsed key, DMP.3
*/
@ProtoField(tag = 6, type = STRING)
public final String token;
/**
* User data + GOOGLE. prefixed special entries, DMP.4
*/
@ProtoField(tag = 7, label = REPEATED, messageType = AppData.class)
public final List<AppData> app_data;
/**
* Not used.
*/
@ProtoField(tag = 8, type = BOOL)
public final Boolean from_trusted_server;
/**
* Part of the ACK protocol, returned in DataMessageResponse on server side.
* It's part of the key of DMP.
*/
@ProtoField(tag = 9, type = STRING)
public final String persistent_id;
/**
* In-stream ack. Increments on each message sent - a bit redundant
* Not used in DMP/DMR.
*/
@ProtoField(tag = 10, type = INT32)
public final Integer stream_id;
@ProtoField(tag = 11, type = INT32)
public final Integer last_stream_id_received;
/**
* Not used.
* optional string permission = 12;
* Sent by the device shortly after registration.
*/
@ProtoField(tag = 13, type = STRING)
public final String reg_id;
/**
* Not used.
* optional string pkg_signature = 14;
* Not used.
* optional string client_id = 15;
* serial number of the target user, DMP.8
* It is the 'serial number' according to user manager.
*/
@ProtoField(tag = 16, type = INT64)
public final Long device_user_id;
/**
* Time to live, in seconds.
*/
@ProtoField(tag = 17, type = INT32)
public final Integer ttl;
/**
* Timestamp ( according to client ) when message was sent by app, in seconds
*/
@ProtoField(tag = 18, type = INT64)
public final Long sent;
/**
* How long has the message been queued before the flush, in seconds.
* This is needed to account for the time difference between server and
* client: server should adjust 'sent' based on his 'receive' time.
*/
@ProtoField(tag = 19, type = INT32)
public final Integer queued;
@ProtoField(tag = 20, type = INT64)
public final Long status;
public DataMessageStanza(String id, String from, String to, String category, String token, List<AppData> app_data, Boolean from_trusted_server, String persistent_id, Integer stream_id, Integer last_stream_id_received, String reg_id, Long device_user_id, Integer ttl, Long sent, Integer queued, Long status) {
this.id = id;
this.from = from;
this.to = to;
this.category = category;
this.token = token;
this.app_data = immutableCopyOf(app_data);
this.from_trusted_server = from_trusted_server;
this.persistent_id = persistent_id;
this.stream_id = stream_id;
this.last_stream_id_received = last_stream_id_received;
this.reg_id = reg_id;
this.device_user_id = device_user_id;
this.ttl = ttl;
this.sent = sent;
this.queued = queued;
this.status = status;
}
private DataMessageStanza(Builder builder) {
this(builder.id, builder.from, builder.to, builder.category, builder.token, builder.app_data, builder.from_trusted_server, builder.persistent_id, builder.stream_id, builder.last_stream_id_received, builder.reg_id, builder.device_user_id, builder.ttl, builder.sent, builder.queued, builder.status);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof DataMessageStanza)) return false;
DataMessageStanza o = (DataMessageStanza) other;
return equals(id, o.id)
&& equals(from, o.from)
&& equals(to, o.to)
&& equals(category, o.category)
&& equals(token, o.token)
&& equals(app_data, o.app_data)
&& equals(from_trusted_server, o.from_trusted_server)
&& equals(persistent_id, o.persistent_id)
&& equals(stream_id, o.stream_id)
&& equals(last_stream_id_received, o.last_stream_id_received)
&& equals(reg_id, o.reg_id)
&& equals(device_user_id, o.device_user_id)
&& equals(ttl, o.ttl)
&& equals(sent, o.sent)
&& equals(queued, o.queued)
&& equals(status, o.status);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = id != null ? id.hashCode() : 0;
result = result * 37 + (from != null ? from.hashCode() : 0);
result = result * 37 + (to != null ? to.hashCode() : 0);
result = result * 37 + (category != null ? category.hashCode() : 0);
result = result * 37 + (token != null ? token.hashCode() : 0);
result = result * 37 + (app_data != null ? app_data.hashCode() : 1);
result = result * 37 + (from_trusted_server != null ? from_trusted_server.hashCode() : 0);
result = result * 37 + (persistent_id != null ? persistent_id.hashCode() : 0);
result = result * 37 + (stream_id != null ? stream_id.hashCode() : 0);
result = result * 37 + (last_stream_id_received != null ? last_stream_id_received.hashCode() : 0);
result = result * 37 + (reg_id != null ? reg_id.hashCode() : 0);
result = result * 37 + (device_user_id != null ? device_user_id.hashCode() : 0);
result = result * 37 + (ttl != null ? ttl.hashCode() : 0);
result = result * 37 + (sent != null ? sent.hashCode() : 0);
result = result * 37 + (queued != null ? queued.hashCode() : 0);
result = result * 37 + (status != null ? status.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<DataMessageStanza> {
public String id;
public String from;
public String to;
public String category;
public String token;
public List<AppData> app_data;
public Boolean from_trusted_server;
public String persistent_id;
public Integer stream_id;
public Integer last_stream_id_received;
public String reg_id;
public Long device_user_id;
public Integer ttl;
public Long sent;
public Integer queued;
public Long status;
public Builder() {
}
public Builder(DataMessageStanza message) {
super(message);
if (message == null) return;
this.id = message.id;
this.from = message.from;
this.to = message.to;
this.category = message.category;
this.token = message.token;
this.app_data = copyOf(message.app_data);
this.from_trusted_server = message.from_trusted_server;
this.persistent_id = message.persistent_id;
this.stream_id = message.stream_id;
this.last_stream_id_received = message.last_stream_id_received;
this.reg_id = message.reg_id;
this.device_user_id = message.device_user_id;
this.ttl = message.ttl;
this.sent = message.sent;
this.queued = message.queued;
this.status = message.status;
}
/**
* Not used.
* optional int64 rmq_id = 1;
* This is the message ID, set by client, DMP.9 (message_id)
*/
public Builder id(String id) {
this.id = id;
return this;
}
/**
* Project ID of the sender, DMP.1
*/
public Builder from(String from) {
this.from = from;
return this;
}
/**
* Part of DMRequest - also the key in DataMessageProto.
*/
public Builder to(String to) {
this.to = to;
return this;
}
/**
* Package name. DMP.2
*/
public Builder category(String category) {
this.category = category;
return this;
}
/**
* The collapsed key, DMP.3
*/
public Builder token(String token) {
this.token = token;
return this;
}
/**
* User data + GOOGLE. prefixed special entries, DMP.4
*/
public Builder app_data(List<AppData> app_data) {
this.app_data = checkForNulls(app_data);
return this;
}
/**
* Not used.
*/
public Builder from_trusted_server(Boolean from_trusted_server) {
this.from_trusted_server = from_trusted_server;
return this;
}
/**
* Part of the ACK protocol, returned in DataMessageResponse on server side.
* It's part of the key of DMP.
*/
public Builder persistent_id(String persistent_id) {
this.persistent_id = persistent_id;
return this;
}
/**
* In-stream ack. Increments on each message sent - a bit redundant
* Not used in DMP/DMR.
*/
public Builder stream_id(Integer stream_id) {
this.stream_id = stream_id;
return this;
}
public Builder last_stream_id_received(Integer last_stream_id_received) {
this.last_stream_id_received = last_stream_id_received;
return this;
}
/**
* Not used.
* optional string permission = 12;
* Sent by the device shortly after registration.
*/
public Builder reg_id(String reg_id) {
this.reg_id = reg_id;
return this;
}
/**
* Not used.
* optional string pkg_signature = 14;
* Not used.
* optional string client_id = 15;
* serial number of the target user, DMP.8
* It is the 'serial number' according to user manager.
*/
public Builder device_user_id(Long device_user_id) {
this.device_user_id = device_user_id;
return this;
}
/**
* Time to live, in seconds.
*/
public Builder ttl(Integer ttl) {
this.ttl = ttl;
return this;
}
/**
* Timestamp ( according to client ) when message was sent by app, in seconds
*/
public Builder sent(Long sent) {
this.sent = sent;
return this;
}
/**
* How long has the message been queued before the flush, in seconds.
* This is needed to account for the time difference between server and
* client: server should adjust 'sent' based on his 'receive' time.
*/
public Builder queued(Integer queued) {
this.queued = queued;
return this;
}
public Builder status(Long status) {
this.status = status;
return this;
}
@Override
public DataMessageStanza build() {
checkRequiredFields();
return new DataMessageStanza(this);
}
}
}

View File

@ -0,0 +1,111 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
public final class ErrorInfo extends Message {
public static final Integer DEFAULT_CODE = 0;
public static final String DEFAULT_MESSAGE = "";
public static final String DEFAULT_TYPE = "";
@ProtoField(tag = 1, type = INT32, label = REQUIRED)
public final Integer code;
@ProtoField(tag = 2, type = STRING)
public final String message;
@ProtoField(tag = 3, type = STRING)
public final String type;
@ProtoField(tag = 4)
public final Extension extension;
public ErrorInfo(Integer code, String message, String type, Extension extension) {
this.code = code;
this.message = message;
this.type = type;
this.extension = extension;
}
private ErrorInfo(Builder builder) {
this(builder.code, builder.message, builder.type, builder.extension);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof ErrorInfo)) return false;
ErrorInfo o = (ErrorInfo) other;
return equals(code, o.code)
&& equals(message, o.message)
&& equals(type, o.type)
&& equals(extension, o.extension);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = code != null ? code.hashCode() : 0;
result = result * 37 + (message != null ? message.hashCode() : 0);
result = result * 37 + (type != null ? type.hashCode() : 0);
result = result * 37 + (extension != null ? extension.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<ErrorInfo> {
public Integer code;
public String message;
public String type;
public Extension extension;
public Builder() {
}
public Builder(ErrorInfo message) {
super(message);
if (message == null) return;
this.code = message.code;
this.message = message.message;
this.type = message.type;
this.extension = message.extension;
}
public Builder code(Integer code) {
this.code = code;
return this;
}
public Builder message(String message) {
this.message = message;
return this;
}
public Builder type(String type) {
this.type = type;
return this;
}
public Builder extension(Extension extension) {
this.extension = extension;
return this;
}
@Override
public ErrorInfo build() {
checkRequiredFields();
return new ErrorInfo(this);
}
}
}

View File

@ -0,0 +1,93 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import okio.ByteString;
import static com.squareup.wire.Message.Datatype.BYTES;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Label.REQUIRED;
public final class Extension extends Message {
public static final Integer DEFAULT_ID = 0;
public static final ByteString DEFAULT_DATA = ByteString.EMPTY;
/**
* 12: SelectiveAck
* 13: StreamAck
*/
@ProtoField(tag = 1, type = INT32, label = REQUIRED)
public final Integer id;
@ProtoField(tag = 2, type = BYTES, label = REQUIRED)
public final ByteString data;
public Extension(Integer id, ByteString data) {
this.id = id;
this.data = data;
}
private Extension(Builder builder) {
this(builder.id, builder.data);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Extension)) return false;
Extension o = (Extension) other;
return equals(id, o.id)
&& equals(data, o.data);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = id != null ? id.hashCode() : 0;
result = result * 37 + (data != null ? data.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<Extension> {
public Integer id;
public ByteString data;
public Builder() {
}
public Builder(Extension message) {
super(message);
if (message == null) return;
this.id = message.id;
this.data = message.data;
}
/**
* 12: SelectiveAck
* 13: StreamAck
*/
public Builder id(Integer id) {
this.id = id;
return this;
}
public Builder data(ByteString data) {
this.data = data;
return this;
}
@Override
public Extension build() {
checkRequiredFields();
return new Extension(this);
}
}
}

View File

@ -0,0 +1,99 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
/**
* TAG: 1
*/
public final class HeartbeatAck extends Message {
public static final Integer DEFAULT_STREAM_ID = 0;
public static final Integer DEFAULT_LAST_STREAM_ID_RECEIVED = 0;
public static final Long DEFAULT_STATUS = 0L;
@ProtoField(tag = 1, type = INT32)
public final Integer stream_id;
@ProtoField(tag = 2, type = INT32)
public final Integer last_stream_id_received;
@ProtoField(tag = 3, type = INT64)
public final Long status;
public HeartbeatAck(Integer stream_id, Integer last_stream_id_received, Long status) {
this.stream_id = stream_id;
this.last_stream_id_received = last_stream_id_received;
this.status = status;
}
private HeartbeatAck(Builder builder) {
this(builder.stream_id, builder.last_stream_id_received, builder.status);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof HeartbeatAck)) return false;
HeartbeatAck o = (HeartbeatAck) other;
return equals(stream_id, o.stream_id)
&& equals(last_stream_id_received, o.last_stream_id_received)
&& equals(status, o.status);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = stream_id != null ? stream_id.hashCode() : 0;
result = result * 37 + (last_stream_id_received != null ? last_stream_id_received.hashCode() : 0);
result = result * 37 + (status != null ? status.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<HeartbeatAck> {
public Integer stream_id;
public Integer last_stream_id_received;
public Long status;
public Builder() {
}
public Builder(HeartbeatAck message) {
super(message);
if (message == null) return;
this.stream_id = message.stream_id;
this.last_stream_id_received = message.last_stream_id_received;
this.status = message.status;
}
public Builder stream_id(Integer stream_id) {
this.stream_id = stream_id;
return this;
}
public Builder last_stream_id_received(Integer last_stream_id_received) {
this.last_stream_id_received = last_stream_id_received;
return this;
}
public Builder status(Long status) {
this.status = status;
return this;
}
@Override
public HeartbeatAck build() {
return new HeartbeatAck(this);
}
}
}

View File

@ -0,0 +1,97 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.BOOL;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.STRING;
public final class HeartbeatConfig extends Message {
public static final Boolean DEFAULT_UPLOAD_STAT = false;
public static final String DEFAULT_IP = "";
public static final Integer DEFAULT_INTERVAL_MS = 0;
@ProtoField(tag = 1, type = BOOL)
public final Boolean upload_stat;
@ProtoField(tag = 2, type = STRING)
public final String ip;
@ProtoField(tag = 3, type = INT32)
public final Integer interval_ms;
public HeartbeatConfig(Boolean upload_stat, String ip, Integer interval_ms) {
this.upload_stat = upload_stat;
this.ip = ip;
this.interval_ms = interval_ms;
}
private HeartbeatConfig(Builder builder) {
this(builder.upload_stat, builder.ip, builder.interval_ms);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof HeartbeatConfig)) return false;
HeartbeatConfig o = (HeartbeatConfig) other;
return equals(upload_stat, o.upload_stat)
&& equals(ip, o.ip)
&& equals(interval_ms, o.interval_ms);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = upload_stat != null ? upload_stat.hashCode() : 0;
result = result * 37 + (ip != null ? ip.hashCode() : 0);
result = result * 37 + (interval_ms != null ? interval_ms.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<HeartbeatConfig> {
public Boolean upload_stat;
public String ip;
public Integer interval_ms;
public Builder() {
}
public Builder(HeartbeatConfig message) {
super(message);
if (message == null) return;
this.upload_stat = message.upload_stat;
this.ip = message.ip;
this.interval_ms = message.interval_ms;
}
public Builder upload_stat(Boolean upload_stat) {
this.upload_stat = upload_stat;
return this;
}
public Builder ip(String ip) {
this.ip = ip;
return this;
}
public Builder interval_ms(Integer interval_ms) {
this.interval_ms = interval_ms;
return this;
}
@Override
public HeartbeatConfig build() {
return new HeartbeatConfig(this);
}
}
}

View File

@ -0,0 +1,105 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
/**
* Common fields/comments:
*
* stream_id: no longer sent by server, each side keeps a counter
* last_stream_id_received: sent only if a packet was received since last time
* a last_stream was sent
* status: new bitmask including the 'idle' as bit 0.
* TAG: 0
*/
public final class HeartbeatPing extends Message {
public static final Integer DEFAULT_STREAM_ID = 0;
public static final Integer DEFAULT_LAST_STREAM_ID_RECEIVED = 0;
public static final Long DEFAULT_STATUS = 0L;
@ProtoField(tag = 1, type = INT32)
public final Integer stream_id;
@ProtoField(tag = 2, type = INT32)
public final Integer last_stream_id_received;
@ProtoField(tag = 3, type = INT64)
public final Long status;
public HeartbeatPing(Integer stream_id, Integer last_stream_id_received, Long status) {
this.stream_id = stream_id;
this.last_stream_id_received = last_stream_id_received;
this.status = status;
}
private HeartbeatPing(Builder builder) {
this(builder.stream_id, builder.last_stream_id_received, builder.status);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof HeartbeatPing)) return false;
HeartbeatPing o = (HeartbeatPing) other;
return equals(stream_id, o.stream_id)
&& equals(last_stream_id_received, o.last_stream_id_received)
&& equals(status, o.status);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = stream_id != null ? stream_id.hashCode() : 0;
result = result * 37 + (last_stream_id_received != null ? last_stream_id_received.hashCode() : 0);
result = result * 37 + (status != null ? status.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<HeartbeatPing> {
public Integer stream_id;
public Integer last_stream_id_received;
public Long status;
public Builder() {
}
public Builder(HeartbeatPing message) {
super(message);
if (message == null) return;
this.stream_id = message.stream_id;
this.last_stream_id_received = message.last_stream_id_received;
this.status = message.status;
}
public Builder stream_id(Integer stream_id) {
this.stream_id = stream_id;
return this;
}
public Builder last_stream_id_received(Integer last_stream_id_received) {
this.last_stream_id_received = last_stream_id_received;
return this;
}
public Builder status(Long status) {
this.status = status;
return this;
}
@Override
public HeartbeatPing build() {
return new HeartbeatPing(this);
}
}
}

View File

@ -0,0 +1,99 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.BOOL;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
public final class HeartbeatStat extends Message {
public static final String DEFAULT_IP = "";
public static final Boolean DEFAULT_TIMEOUT = false;
public static final Integer DEFAULT_INTERVAL_MS = 0;
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String ip;
@ProtoField(tag = 2, type = BOOL, label = REQUIRED)
public final Boolean timeout;
@ProtoField(tag = 3, type = INT32, label = REQUIRED)
public final Integer interval_ms;
public HeartbeatStat(String ip, Boolean timeout, Integer interval_ms) {
this.ip = ip;
this.timeout = timeout;
this.interval_ms = interval_ms;
}
private HeartbeatStat(Builder builder) {
this(builder.ip, builder.timeout, builder.interval_ms);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof HeartbeatStat)) return false;
HeartbeatStat o = (HeartbeatStat) other;
return equals(ip, o.ip)
&& equals(timeout, o.timeout)
&& equals(interval_ms, o.interval_ms);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = ip != null ? ip.hashCode() : 0;
result = result * 37 + (timeout != null ? timeout.hashCode() : 0);
result = result * 37 + (interval_ms != null ? interval_ms.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<HeartbeatStat> {
public String ip;
public Boolean timeout;
public Integer interval_ms;
public Builder() {
}
public Builder(HeartbeatStat message) {
super(message);
if (message == null) return;
this.ip = message.ip;
this.timeout = message.timeout;
this.interval_ms = message.interval_ms;
}
public Builder ip(String ip) {
this.ip = ip;
return this;
}
public Builder timeout(Boolean timeout) {
this.timeout = timeout;
return this;
}
public Builder interval_ms(Integer interval_ms) {
this.interval_ms = interval_ms;
return this;
}
@Override
public HeartbeatStat build() {
checkRequiredFields();
return new HeartbeatStat(this);
}
}
}

View File

@ -0,0 +1,255 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoEnum;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.ENUM;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
/**
* TAG: 7
* IqRequest must contain a single extension. IqResponse may contain 0 or 1
* extensions.
*/
public final class IqStanza extends Message {
public static final Long DEFAULT_RMQ_ID = 0L;
public static final IqType DEFAULT_TYPE = IqType.GET;
public static final String DEFAULT_ID = "";
public static final String DEFAULT_FROM = "";
public static final String DEFAULT_TO = "";
public static final String DEFAULT_PERSISTENT_ID = "";
public static final Integer DEFAULT_STREAM_ID = 0;
public static final Integer DEFAULT_LAST_STREAM_ID_RECEIVED = 0;
public static final Long DEFAULT_ACCOUNT_ID = 0L;
public static final Long DEFAULT_STATUS = 0L;
@ProtoField(tag = 1, type = INT64)
public final Long rmq_id;
@ProtoField(tag = 2, type = ENUM, label = REQUIRED)
public final IqType type;
@ProtoField(tag = 3, type = STRING, label = REQUIRED)
public final String id;
@ProtoField(tag = 4, type = STRING)
public final String from;
@ProtoField(tag = 5, type = STRING)
public final String to;
@ProtoField(tag = 6)
public final ErrorInfo error;
/**
* Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)
*/
@ProtoField(tag = 7)
public final Extension extension;
@ProtoField(tag = 8, type = STRING)
public final String persistent_id;
@ProtoField(tag = 9, type = INT32)
public final Integer stream_id;
@ProtoField(tag = 10, type = INT32)
public final Integer last_stream_id_received;
@ProtoField(tag = 11, type = INT64)
public final Long account_id;
@ProtoField(tag = 12, type = INT64)
public final Long status;
public IqStanza(Long rmq_id, IqType type, String id, String from, String to, ErrorInfo error, Extension extension, String persistent_id, Integer stream_id, Integer last_stream_id_received, Long account_id, Long status) {
this.rmq_id = rmq_id;
this.type = type;
this.id = id;
this.from = from;
this.to = to;
this.error = error;
this.extension = extension;
this.persistent_id = persistent_id;
this.stream_id = stream_id;
this.last_stream_id_received = last_stream_id_received;
this.account_id = account_id;
this.status = status;
}
private IqStanza(Builder builder) {
this(builder.rmq_id, builder.type, builder.id, builder.from, builder.to, builder.error, builder.extension, builder.persistent_id, builder.stream_id, builder.last_stream_id_received, builder.account_id, builder.status);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof IqStanza)) return false;
IqStanza o = (IqStanza) other;
return equals(rmq_id, o.rmq_id)
&& equals(type, o.type)
&& equals(id, o.id)
&& equals(from, o.from)
&& equals(to, o.to)
&& equals(error, o.error)
&& equals(extension, o.extension)
&& equals(persistent_id, o.persistent_id)
&& equals(stream_id, o.stream_id)
&& equals(last_stream_id_received, o.last_stream_id_received)
&& equals(account_id, o.account_id)
&& equals(status, o.status);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = rmq_id != null ? rmq_id.hashCode() : 0;
result = result * 37 + (type != null ? type.hashCode() : 0);
result = result * 37 + (id != null ? id.hashCode() : 0);
result = result * 37 + (from != null ? from.hashCode() : 0);
result = result * 37 + (to != null ? to.hashCode() : 0);
result = result * 37 + (error != null ? error.hashCode() : 0);
result = result * 37 + (extension != null ? extension.hashCode() : 0);
result = result * 37 + (persistent_id != null ? persistent_id.hashCode() : 0);
result = result * 37 + (stream_id != null ? stream_id.hashCode() : 0);
result = result * 37 + (last_stream_id_received != null ? last_stream_id_received.hashCode() : 0);
result = result * 37 + (account_id != null ? account_id.hashCode() : 0);
result = result * 37 + (status != null ? status.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<IqStanza> {
public Long rmq_id;
public IqType type;
public String id;
public String from;
public String to;
public ErrorInfo error;
public Extension extension;
public String persistent_id;
public Integer stream_id;
public Integer last_stream_id_received;
public Long account_id;
public Long status;
public Builder() {
}
public Builder(IqStanza message) {
super(message);
if (message == null) return;
this.rmq_id = message.rmq_id;
this.type = message.type;
this.id = message.id;
this.from = message.from;
this.to = message.to;
this.error = message.error;
this.extension = message.extension;
this.persistent_id = message.persistent_id;
this.stream_id = message.stream_id;
this.last_stream_id_received = message.last_stream_id_received;
this.account_id = message.account_id;
this.status = message.status;
}
public Builder rmq_id(Long rmq_id) {
this.rmq_id = rmq_id;
return this;
}
public Builder type(IqType type) {
this.type = type;
return this;
}
public Builder id(String id) {
this.id = id;
return this;
}
public Builder from(String from) {
this.from = from;
return this;
}
public Builder to(String to) {
this.to = to;
return this;
}
public Builder error(ErrorInfo error) {
this.error = error;
return this;
}
/**
* Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)
*/
public Builder extension(Extension extension) {
this.extension = extension;
return this;
}
public Builder persistent_id(String persistent_id) {
this.persistent_id = persistent_id;
return this;
}
public Builder stream_id(Integer stream_id) {
this.stream_id = stream_id;
return this;
}
public Builder last_stream_id_received(Integer last_stream_id_received) {
this.last_stream_id_received = last_stream_id_received;
return this;
}
public Builder account_id(Long account_id) {
this.account_id = account_id;
return this;
}
public Builder status(Long status) {
this.status = status;
return this;
}
@Override
public IqStanza build() {
checkRequiredFields();
return new IqStanza(this);
}
}
public enum IqType
implements ProtoEnum {
GET(0),
SET(1),
RESULT(2),
IQ_ERROR(3);
private final int value;
private IqType(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
}

View File

@ -0,0 +1,367 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoEnum;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;
import static com.squareup.wire.Message.Datatype.BOOL;
import static com.squareup.wire.Message.Datatype.ENUM;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REPEATED;
import static com.squareup.wire.Message.Label.REQUIRED;
/**
* TAG: 2
*/
public final class LoginRequest extends Message {
public static final String DEFAULT_ID = "";
public static final String DEFAULT_DOMAIN = "";
public static final String DEFAULT_USER = "";
public static final String DEFAULT_RESOURCE = "";
public static final String DEFAULT_AUTH_TOKEN = "";
public static final String DEFAULT_DEVICE_ID = "";
public static final Long DEFAULT_LAST_RMQ_ID = 0L;
public static final List<Setting> DEFAULT_SETTING = Collections.emptyList();
public static final List<String> DEFAULT_RECEIVED_PERSISTENT_ID = Collections.emptyList();
public static final Boolean DEFAULT_ADAPTIVE_HEARTBEAT = false;
public static final Boolean DEFAULT_USE_RMQ2 = false;
public static final Long DEFAULT_ACCOUNT_ID = 0L;
public static final AuthService DEFAULT_AUTH_SERVICE = AuthService.ANDROID_ID;
public static final Integer DEFAULT_NETWORK_TYPE = 0;
public static final Long DEFAULT_STATUS = 0L;
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String id;
/**
* Must be present ( proto required ), may be empty
* string.
* mcs.android.com.
*/
@ProtoField(tag = 2, type = STRING, label = REQUIRED)
public final String domain;
/**
* Decimal android ID
*/
@ProtoField(tag = 3, type = STRING, label = REQUIRED)
public final String user;
@ProtoField(tag = 4, type = STRING, label = REQUIRED)
public final String resource;
/**
* Secret
*/
@ProtoField(tag = 5, type = STRING, label = REQUIRED)
public final String auth_token;
/**
* Format is: android-HEX_DEVICE_ID
* The user is the decimal value.
*/
@ProtoField(tag = 6, type = STRING)
public final String device_id;
/**
* RMQ1 - no longer used
*/
@ProtoField(tag = 7, type = INT64)
public final Long last_rmq_id;
@ProtoField(tag = 8, label = REPEATED, messageType = Setting.class)
public final List<Setting> setting;
/**
* optional int32 compress = 9;
*/
@ProtoField(tag = 10, type = STRING, label = REPEATED)
public final List<String> received_persistent_id;
/**
* Replaced by "rmq2v" setting
* optional bool include_stream_ids = 11;
*/
@ProtoField(tag = 12, type = BOOL)
public final Boolean adaptive_heartbeat;
@ProtoField(tag = 13)
public final HeartbeatStat heartbeat_stat;
/**
* Must be true.
*/
@ProtoField(tag = 14, type = BOOL)
public final Boolean use_rmq2;
@ProtoField(tag = 15, type = INT64)
public final Long account_id;
/**
* ANDROID_ID = 2
*/
@ProtoField(tag = 16, type = ENUM)
public final AuthService auth_service;
@ProtoField(tag = 17, type = INT32)
public final Integer network_type;
@ProtoField(tag = 18, type = INT64)
public final Long status;
public LoginRequest(String id, String domain, String user, String resource, String auth_token, String device_id, Long last_rmq_id, List<Setting> setting, List<String> received_persistent_id, Boolean adaptive_heartbeat, HeartbeatStat heartbeat_stat, Boolean use_rmq2, Long account_id, AuthService auth_service, Integer network_type, Long status) {
this.id = id;
this.domain = domain;
this.user = user;
this.resource = resource;
this.auth_token = auth_token;
this.device_id = device_id;
this.last_rmq_id = last_rmq_id;
this.setting = immutableCopyOf(setting);
this.received_persistent_id = immutableCopyOf(received_persistent_id);
this.adaptive_heartbeat = adaptive_heartbeat;
this.heartbeat_stat = heartbeat_stat;
this.use_rmq2 = use_rmq2;
this.account_id = account_id;
this.auth_service = auth_service;
this.network_type = network_type;
this.status = status;
}
private LoginRequest(Builder builder) {
this(builder.id, builder.domain, builder.user, builder.resource, builder.auth_token, builder.device_id, builder.last_rmq_id, builder.setting, builder.received_persistent_id, builder.adaptive_heartbeat, builder.heartbeat_stat, builder.use_rmq2, builder.account_id, builder.auth_service, builder.network_type, builder.status);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof LoginRequest)) return false;
LoginRequest o = (LoginRequest) other;
return equals(id, o.id)
&& equals(domain, o.domain)
&& equals(user, o.user)
&& equals(resource, o.resource)
&& equals(auth_token, o.auth_token)
&& equals(device_id, o.device_id)
&& equals(last_rmq_id, o.last_rmq_id)
&& equals(setting, o.setting)
&& equals(received_persistent_id, o.received_persistent_id)
&& equals(adaptive_heartbeat, o.adaptive_heartbeat)
&& equals(heartbeat_stat, o.heartbeat_stat)
&& equals(use_rmq2, o.use_rmq2)
&& equals(account_id, o.account_id)
&& equals(auth_service, o.auth_service)
&& equals(network_type, o.network_type)
&& equals(status, o.status);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = id != null ? id.hashCode() : 0;
result = result * 37 + (domain != null ? domain.hashCode() : 0);
result = result * 37 + (user != null ? user.hashCode() : 0);
result = result * 37 + (resource != null ? resource.hashCode() : 0);
result = result * 37 + (auth_token != null ? auth_token.hashCode() : 0);
result = result * 37 + (device_id != null ? device_id.hashCode() : 0);
result = result * 37 + (last_rmq_id != null ? last_rmq_id.hashCode() : 0);
result = result * 37 + (setting != null ? setting.hashCode() : 1);
result = result * 37 + (received_persistent_id != null ? received_persistent_id.hashCode() : 1);
result = result * 37 + (adaptive_heartbeat != null ? adaptive_heartbeat.hashCode() : 0);
result = result * 37 + (heartbeat_stat != null ? heartbeat_stat.hashCode() : 0);
result = result * 37 + (use_rmq2 != null ? use_rmq2.hashCode() : 0);
result = result * 37 + (account_id != null ? account_id.hashCode() : 0);
result = result * 37 + (auth_service != null ? auth_service.hashCode() : 0);
result = result * 37 + (network_type != null ? network_type.hashCode() : 0);
result = result * 37 + (status != null ? status.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<LoginRequest> {
public String id;
public String domain;
public String user;
public String resource;
public String auth_token;
public String device_id;
public Long last_rmq_id;
public List<Setting> setting;
public List<String> received_persistent_id;
public Boolean adaptive_heartbeat;
public HeartbeatStat heartbeat_stat;
public Boolean use_rmq2;
public Long account_id;
public AuthService auth_service;
public Integer network_type;
public Long status;
public Builder() {
}
public Builder(LoginRequest message) {
super(message);
if (message == null) return;
this.id = message.id;
this.domain = message.domain;
this.user = message.user;
this.resource = message.resource;
this.auth_token = message.auth_token;
this.device_id = message.device_id;
this.last_rmq_id = message.last_rmq_id;
this.setting = copyOf(message.setting);
this.received_persistent_id = copyOf(message.received_persistent_id);
this.adaptive_heartbeat = message.adaptive_heartbeat;
this.heartbeat_stat = message.heartbeat_stat;
this.use_rmq2 = message.use_rmq2;
this.account_id = message.account_id;
this.auth_service = message.auth_service;
this.network_type = message.network_type;
this.status = message.status;
}
public Builder id(String id) {
this.id = id;
return this;
}
/**
* Must be present ( proto required ), may be empty
* string.
* mcs.android.com.
*/
public Builder domain(String domain) {
this.domain = domain;
return this;
}
/**
* Decimal android ID
*/
public Builder user(String user) {
this.user = user;
return this;
}
public Builder resource(String resource) {
this.resource = resource;
return this;
}
/**
* Secret
*/
public Builder auth_token(String auth_token) {
this.auth_token = auth_token;
return this;
}
/**
* Format is: android-HEX_DEVICE_ID
* The user is the decimal value.
*/
public Builder device_id(String device_id) {
this.device_id = device_id;
return this;
}
/**
* RMQ1 - no longer used
*/
public Builder last_rmq_id(Long last_rmq_id) {
this.last_rmq_id = last_rmq_id;
return this;
}
public Builder setting(List<Setting> setting) {
this.setting = checkForNulls(setting);
return this;
}
/**
* optional int32 compress = 9;
*/
public Builder received_persistent_id(List<String> received_persistent_id) {
this.received_persistent_id = checkForNulls(received_persistent_id);
return this;
}
/**
* Replaced by "rmq2v" setting
* optional bool include_stream_ids = 11;
*/
public Builder adaptive_heartbeat(Boolean adaptive_heartbeat) {
this.adaptive_heartbeat = adaptive_heartbeat;
return this;
}
public Builder heartbeat_stat(HeartbeatStat heartbeat_stat) {
this.heartbeat_stat = heartbeat_stat;
return this;
}
/**
* Must be true.
*/
public Builder use_rmq2(Boolean use_rmq2) {
this.use_rmq2 = use_rmq2;
return this;
}
public Builder account_id(Long account_id) {
this.account_id = account_id;
return this;
}
/**
* ANDROID_ID = 2
*/
public Builder auth_service(AuthService auth_service) {
this.auth_service = auth_service;
return this;
}
public Builder network_type(Integer network_type) {
this.network_type = network_type;
return this;
}
public Builder status(Long status) {
this.status = status;
return this;
}
@Override
public LoginRequest build() {
checkRequiredFields();
return new LoginRequest(this);
}
}
public enum AuthService
implements ProtoEnum {
ANDROID_ID(2);
private final int value;
private AuthService(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
}
}

View File

@ -0,0 +1,197 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;
import static com.squareup.wire.Message.Datatype.INT32;
import static com.squareup.wire.Message.Datatype.INT64;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REPEATED;
import static com.squareup.wire.Message.Label.REQUIRED;
/**
* TAG: 3
*/
public final class LoginResponse extends Message {
public static final String DEFAULT_ID = "";
public static final String DEFAULT_JID = "";
public static final List<Setting> DEFAULT_SETTING = Collections.emptyList();
public static final Integer DEFAULT_STREAM_ID = 0;
public static final Integer DEFAULT_LAST_STREAM_ID_RECEIVED = 0;
public static final Long DEFAULT_SERVER_TIMESTAMP = 0L;
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String id;
/**
* Not used.
*/
@ProtoField(tag = 2, type = STRING)
public final String jid;
/**
* Null if login was ok.
*/
@ProtoField(tag = 3)
public final ErrorInfo error;
@ProtoField(tag = 4, label = REPEATED, messageType = Setting.class)
public final List<Setting> setting;
@ProtoField(tag = 5, type = INT32)
public final Integer stream_id;
/**
* Should be "1"
*/
@ProtoField(tag = 6, type = INT32)
public final Integer last_stream_id_received;
@ProtoField(tag = 7)
public final HeartbeatConfig heartbeat_config;
/**
* used by the client to synchronize with the server timestamp.
*/
@ProtoField(tag = 8, type = INT64)
public final Long server_timestamp;
public LoginResponse(String id, String jid, ErrorInfo error, List<Setting> setting, Integer stream_id, Integer last_stream_id_received, HeartbeatConfig heartbeat_config, Long server_timestamp) {
this.id = id;
this.jid = jid;
this.error = error;
this.setting = immutableCopyOf(setting);
this.stream_id = stream_id;
this.last_stream_id_received = last_stream_id_received;
this.heartbeat_config = heartbeat_config;
this.server_timestamp = server_timestamp;
}
private LoginResponse(Builder builder) {
this(builder.id, builder.jid, builder.error, builder.setting, builder.stream_id, builder.last_stream_id_received, builder.heartbeat_config, builder.server_timestamp);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof LoginResponse)) return false;
LoginResponse o = (LoginResponse) other;
return equals(id, o.id)
&& equals(jid, o.jid)
&& equals(error, o.error)
&& equals(setting, o.setting)
&& equals(stream_id, o.stream_id)
&& equals(last_stream_id_received, o.last_stream_id_received)
&& equals(heartbeat_config, o.heartbeat_config)
&& equals(server_timestamp, o.server_timestamp);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = id != null ? id.hashCode() : 0;
result = result * 37 + (jid != null ? jid.hashCode() : 0);
result = result * 37 + (error != null ? error.hashCode() : 0);
result = result * 37 + (setting != null ? setting.hashCode() : 1);
result = result * 37 + (stream_id != null ? stream_id.hashCode() : 0);
result = result * 37 + (last_stream_id_received != null ? last_stream_id_received.hashCode() : 0);
result = result * 37 + (heartbeat_config != null ? heartbeat_config.hashCode() : 0);
result = result * 37 + (server_timestamp != null ? server_timestamp.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<LoginResponse> {
public String id;
public String jid;
public ErrorInfo error;
public List<Setting> setting;
public Integer stream_id;
public Integer last_stream_id_received;
public HeartbeatConfig heartbeat_config;
public Long server_timestamp;
public Builder() {
}
public Builder(LoginResponse message) {
super(message);
if (message == null) return;
this.id = message.id;
this.jid = message.jid;
this.error = message.error;
this.setting = copyOf(message.setting);
this.stream_id = message.stream_id;
this.last_stream_id_received = message.last_stream_id_received;
this.heartbeat_config = message.heartbeat_config;
this.server_timestamp = message.server_timestamp;
}
public Builder id(String id) {
this.id = id;
return this;
}
/**
* Not used.
*/
public Builder jid(String jid) {
this.jid = jid;
return this;
}
/**
* Null if login was ok.
*/
public Builder error(ErrorInfo error) {
this.error = error;
return this;
}
public Builder setting(List<Setting> setting) {
this.setting = checkForNulls(setting);
return this;
}
public Builder stream_id(Integer stream_id) {
this.stream_id = stream_id;
return this;
}
/**
* Should be "1"
*/
public Builder last_stream_id_received(Integer last_stream_id_received) {
this.last_stream_id_received = last_stream_id_received;
return this;
}
public Builder heartbeat_config(HeartbeatConfig heartbeat_config) {
this.heartbeat_config = heartbeat_config;
return this;
}
/**
* used by the client to synchronize with the server timestamp.
*/
public Builder server_timestamp(Long server_timestamp) {
this.server_timestamp = server_timestamp;
return this;
}
@Override
public LoginResponse build() {
checkRequiredFields();
return new LoginResponse(this);
}
}
}

View File

@ -0,0 +1,68 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import java.util.Collections;
import java.util.List;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REPEATED;
/**
* Included in IQ sent after LoginResponse from server with ID 12.
*/
public final class SelectiveAck extends Message {
public static final List<String> DEFAULT_ID = Collections.emptyList();
@ProtoField(tag = 1, type = STRING, label = REPEATED)
public final List<String> id;
public SelectiveAck(List<String> id) {
this.id = immutableCopyOf(id);
}
private SelectiveAck(Builder builder) {
this(builder.id);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof SelectiveAck)) return false;
return equals(id, ((SelectiveAck) other).id);
}
@Override
public int hashCode() {
int result = hashCode;
return result != 0 ? result : (hashCode = id != null ? id.hashCode() : 1);
}
public static final class Builder extends Message.Builder<SelectiveAck> {
public List<String> id;
public Builder() {
}
public Builder(SelectiveAck message) {
super(message);
if (message == null) return;
this.id = copyOf(message.id);
}
public Builder id(List<String> id) {
this.id = checkForNulls(id);
return this;
}
@Override
public SelectiveAck build() {
return new SelectiveAck(this);
}
}
}

View File

@ -0,0 +1,90 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
/**
* MobileSettings class.
* "u:f", "u:b", "u:s" - multi user devices reporting foreground, background
* and stopped users.
* hbping: heatbeat ping interval
* rmq2v: include explicit stream IDs
*/
public final class Setting extends Message {
public static final String DEFAULT_NAME = "";
public static final String DEFAULT_VALUE = "";
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String name;
@ProtoField(tag = 2, type = STRING, label = REQUIRED)
public final String value;
public Setting(String name, String value) {
this.name = name;
this.value = value;
}
private Setting(Builder builder) {
this(builder.name, builder.value);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Setting)) return false;
Setting o = (Setting) other;
return equals(name, o.name)
&& equals(value, o.value);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = name != null ? name.hashCode() : 0;
result = result * 37 + (value != null ? value.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<Setting> {
public String name;
public String value;
public Builder() {
}
public Builder(Setting message) {
super(message);
if (message == null) return;
this.name = message.name;
this.value = message.value;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder value(String value) {
this.value = value;
return this;
}
@Override
public Setting build() {
checkRequiredFields();
return new Setting(this);
}
}
}

View File

@ -0,0 +1,44 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
/**
* Included in IQ with ID 13, sent from client or server after 10 unconfirmed
* messages.
*/
public final class StreamAck extends Message {
public StreamAck() {
}
private StreamAck(Builder builder) {
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
return other instanceof StreamAck;
}
@Override
public int hashCode() {
return 0;
}
public static final class Builder extends Message.Builder<StreamAck> {
public Builder() {
}
public Builder(StreamAck message) {
super(message);
}
@Override
public StreamAck build() {
return new StreamAck(this);
}
}
}

View File

@ -0,0 +1,83 @@
// Code generated by Wire protocol buffer compiler, do not edit.
// Source file: protos-repo/mcs.proto
package org.microg.gms.gcm.mcs;
import com.squareup.wire.Message;
import com.squareup.wire.ProtoField;
import static com.squareup.wire.Message.Datatype.STRING;
import static com.squareup.wire.Message.Label.REQUIRED;
public final class StreamErrorStanza extends Message {
public static final String DEFAULT_TYPE = "";
public static final String DEFAULT_TEXT = "";
@ProtoField(tag = 1, type = STRING, label = REQUIRED)
public final String type;
@ProtoField(tag = 2, type = STRING)
public final String text;
public StreamErrorStanza(String type, String text) {
this.type = type;
this.text = text;
}
private StreamErrorStanza(Builder builder) {
this(builder.type, builder.text);
setBuilder(builder);
}
@Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof StreamErrorStanza)) return false;
StreamErrorStanza o = (StreamErrorStanza) other;
return equals(type, o.type)
&& equals(text, o.text);
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = type != null ? type.hashCode() : 0;
result = result * 37 + (text != null ? text.hashCode() : 0);
hashCode = result;
}
return result;
}
public static final class Builder extends Message.Builder<StreamErrorStanza> {
public String type;
public String text;
public Builder() {
}
public Builder(StreamErrorStanza message) {
super(message);
if (message == null) return;
this.type = message.type;
this.text = message.text;
}
public Builder type(String type) {
this.type = type;
return this;
}
public Builder text(String text) {
this.text = text;
return this;
}
@Override
public StreamErrorStanza build() {
checkRequiredFields();
return new StreamErrorStanza(this);
}
}
}

View File

@ -0,0 +1,266 @@
// Derived from mcs.proto in chromium source code. Original license text below.
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// MCS protocol for communication between Chrome client and Mobile Connection
// Server .
option java_package = "org.microg.gms.gcm.mcs";
/*
Common fields/comments:
stream_id: no longer sent by server, each side keeps a counter
last_stream_id_received: sent only if a packet was received since last time
a last_stream was sent
status: new bitmask including the 'idle' as bit 0.
*/
/**
TAG: 0
*/
message HeartbeatPing {
optional int32 stream_id = 1;
optional int32 last_stream_id_received = 2;
optional int64 status = 3;
}
/**
TAG: 1
*/
message HeartbeatAck {
optional int32 stream_id = 1;
optional int32 last_stream_id_received = 2;
optional int64 status = 3;
}
message ErrorInfo {
required int32 code = 1;
optional string message = 2;
optional string type = 3;
optional Extension extension = 4;
}
// MobileSettings class.
// "u:f", "u:b", "u:s" - multi user devices reporting foreground, background
// and stopped users.
// hbping: heatbeat ping interval
// rmq2v: include explicit stream IDs
message Setting {
required string name = 1;
required string value = 2;
}
message HeartbeatStat {
required string ip = 1;
required bool timeout = 2;
required int32 interval_ms = 3;
}
message HeartbeatConfig {
optional bool upload_stat = 1;
optional string ip = 2;
optional int32 interval_ms = 3;
}
/**
TAG: 2
*/
message LoginRequest {
enum AuthService {
ANDROID_ID = 2;
}
required string id = 1; // Must be present ( proto required ), may be empty
// string.
// mcs.android.com.
required string domain = 2;
// Decimal android ID
required string user = 3;
required string resource = 4;
// Secret
required string auth_token = 5;
// Format is: android-HEX_DEVICE_ID
// The user is the decimal value.
optional string device_id = 6;
// RMQ1 - no longer used
optional int64 last_rmq_id = 7;
repeated Setting setting = 8;
//optional int32 compress = 9;
repeated string received_persistent_id = 10;
// Replaced by "rmq2v" setting
// optional bool include_stream_ids = 11;
optional bool adaptive_heartbeat = 12;
optional HeartbeatStat heartbeat_stat = 13;
// Must be true.
optional bool use_rmq2 = 14;
optional int64 account_id = 15;
// ANDROID_ID = 2
optional AuthService auth_service = 16;
optional int32 network_type = 17;
optional int64 status = 18;
}
/**
* TAG: 3
*/
message LoginResponse {
required string id = 1;
// Not used.
optional string jid = 2;
// Null if login was ok.
optional ErrorInfo error = 3;
repeated Setting setting = 4;
optional int32 stream_id = 5;
// Should be "1"
optional int32 last_stream_id_received = 6;
optional HeartbeatConfig heartbeat_config = 7;
// used by the client to synchronize with the server timestamp.
optional int64 server_timestamp = 8;
}
message StreamErrorStanza {
required string type = 1;
optional string text = 2;
}
/**
* TAG: 4
*/
message Close {
}
message Extension {
// 12: SelectiveAck
// 13: StreamAck
required int32 id = 1;
required bytes data = 2;
}
/**
* TAG: 7
* IqRequest must contain a single extension. IqResponse may contain 0 or 1
* extensions.
*/
message IqStanza {
enum IqType {
GET = 0;
SET = 1;
RESULT = 2;
IQ_ERROR = 3;
}
optional int64 rmq_id = 1;
required IqType type = 2;
required string id = 3;
optional string from = 4;
optional string to = 5;
optional ErrorInfo error = 6;
// Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)
optional Extension extension = 7;
optional string persistent_id = 8;
optional int32 stream_id = 9;
optional int32 last_stream_id_received = 10;
optional int64 account_id = 11;
optional int64 status = 12;
}
message AppData {
required string key = 1;
required string value = 2;
}
/**
* TAG: 8
*/
message DataMessageStanza {
// Not used.
// optional int64 rmq_id = 1;
// This is the message ID, set by client, DMP.9 (message_id)
optional string id = 2;
// Project ID of the sender, DMP.1
required string from = 3;
// Part of DMRequest - also the key in DataMessageProto.
optional string to = 4;
// Package name. DMP.2
required string category = 5;
// The collapsed key, DMP.3
optional string token = 6;
// User data + GOOGLE. prefixed special entries, DMP.4
repeated AppData app_data = 7;
// Not used.
optional bool from_trusted_server = 8;
// Part of the ACK protocol, returned in DataMessageResponse on server side.
// It's part of the key of DMP.
optional string persistent_id = 9;
// In-stream ack. Increments on each message sent - a bit redundant
// Not used in DMP/DMR.
optional int32 stream_id = 10;
optional int32 last_stream_id_received = 11;
// Not used.
// optional string permission = 12;
// Sent by the device shortly after registration.
optional string reg_id = 13;
// Not used.
// optional string pkg_signature = 14;
// Not used.
// optional string client_id = 15;
// serial number of the target user, DMP.8
// It is the 'serial number' according to user manager.
optional int64 device_user_id = 16;
// Time to live, in seconds.
optional int32 ttl = 17;
// Timestamp ( according to client ) when message was sent by app, in seconds
optional int64 sent = 18;
// How long has the message been queued before the flush, in seconds.
// This is needed to account for the time difference between server and
// client: server should adjust 'sent' based on his 'receive' time.
optional int32 queued = 19;
optional int64 status = 20;
}
/**
Included in IQ with ID 13, sent from client or server after 10 unconfirmed
messages.
*/
message StreamAck {
// No last_streamid_received required. This is included within an IqStanza,
// which includes the last_stream_id_received.
}
/**
Included in IQ sent after LoginResponse from server with ID 12.
*/
message SelectiveAck {
repeated string id = 1;
}