private void TL_RpcError(TL.Object obj) { int code = obj.getInt("error_code"); String msg = obj.getString("error_message"); Common.logError(String.format("rpc_error: %s (%d)\n", msg, code)); Message req_msg = TLMessage.get(req_msg_id); if (req_msg == null) return; Common.logError("message object: " + req_msg.obj.name + ":" + req_msg.obj.type); int idx = msg.indexOf("_MIGRATE_"); if (idx > 0) { String type = msg.substring(0, idx); String num = msg.substring(idx + 9); if ((idx = num.indexOf(":")) > 0) num = num.substring(0, idx); int dc_id = Integer.parseInt(num); Common.logError("redirect to dc: " + dc_id); MTProto m = MTProto.getConnection(dc_id, cb, reuseFlag); cb.onRedirect(m); if (type.equals("PHONE") || type.equals("NETWORK") || type.equals("USER")) dc_this = dc_id; m.sendMessage(req_msg); } }
private void TL_BadMsgNotification(TL.Object obj) { int error_code = obj.getInt("error_code"); Message msg = TLMessage.get(obj.getLong("bad_msg_id")); Common.logError("bad_msg: " + error_code + " " + msg.obj.name + ":" + msg.obj.type); if (error_code == 16 || error_code == 17) { time_delta = (int) ((cur_message_id >> 32) - Common.getUnixTime()); last_message_id = 0; } if (error_code == 32 || error_code == 33) { Common.logError("cur seq: " + cur_msg_seq); Common.logError("old seq: " + seqno); if (!bad_seq) { session = GEN_session_id(); seqno = 0; send_ping(); bad_seq = true; } // seqno = cur_msg_seq + (cur_msg_seq % 2) + 100; // session = GEN_session_id(); // seqno = 0; } if (obj.id == 0xedab447b) { // bad_server_salt server_salt = obj.getLong("new_server_salt"); dcState.set("server_salt", server_salt); } retry(obj.getLong("bad_msg_id")); }
private void send_client_DH_inner_data(long retry_id) { byte[] b_data = new byte[256]; Common.random.nextBytes(b_data); BigInteger b = new BigInteger(1, b_data); BigInteger g_b = g.modPow(b, dh_prime); Common.logError( "g_b length: " + g_b.toByteArray().length + " -> " + Common.toBytes(g_b).length); BigInteger akey = g_a.modPow(b, dh_prime); Common.logError("auth_key: " + akey.toString()); setAuthKey(Common.toBytes(akey)); // gen data (client_DH_inner_data) TL.Object data_obj = TL.newObject("client_DH_inner_data", cl_nonce, sv_nonce, retry_id, g_b); byte[] data = data_obj.serialize(); byte[] hash = Common.getSHA1(data); byte[] data_with_hash = new byte[(hash.length + data.length + 15) / 16 * 16]; System.arraycopy(hash, 0, data_with_hash, 0, hash.length); System.arraycopy(data, 0, data_with_hash, hash.length, data.length); // send set_client_DH_params TL.Object req_obj = TL.newObject("set_client_DH_params", cl_nonce, sv_nonce, aes.IGE(data_with_hash, true)); send(req_obj, false, false); }
public void onReceive(ByteBuffer b) { if (b.remaining() == 4) { Common.logError("invalid packet:"); byte[] data = new byte[b.remaining()]; b.get(data); Common.print_dump(data); // retry( TLMessage.keyAt( TLMessage.size() - 1) ); return; } try { if (b.getLong() == 0) { // auth_key_id b.getLong(); // message_id b.getInt(); // message length process(TL.deserialize(b)); } else { byte[] msg_key = new byte[16]; b.get(msg_key); byte[] data = new byte[b.remaining()]; b.get(data); synchronized (aes) { aes.prepare(false, msg_key, auth_key); data = aes.IGE(data, false); } ByteBuffer btmp = ByteBuffer.wrap(data); btmp.order(ByteOrder.LITTLE_ENDIAN); server_salt = btmp.getLong(); btmp.getLong(); // session_id cur_message_id = btmp.getLong(); // message_id cur_msg_seq = btmp.getInt(); // seq_no // if (cur_msg_seq > seqno) // seqno = cur_msg_seq + cur_msg_seq % 2; int bsize = btmp.getInt(); if (bsize < 0 || bsize > 1024 * 1024) { Common.print_dump(btmp.array()); Common.logError(new String(btmp.array())); Common.logError("FFFUUUUUUUUUUU!!!"); } b = BufferAlloc(bsize); btmp.get(b.array()); b.getInt(); ack_message(cur_msg_seq, cur_message_id); b.position(0); process(TL.deserialize(b)); send_accept(); } } catch (Exception e) { e.printStackTrace(); } }
public void retry(long message_id) { Common.logError("retry"); Message msg = TLMessage.get(message_id); if (msg == null) return; TLMessage.delete(message_id); sendMessage(msg); }
public void onAuthorized() { dcState.set("auth_key", auth_key); dcState.set("server_salt", server_salt); long upd_delta = (long) Common.getUnixTime() - (long) dc_date; if (Main.mtp == this && upd_delta > 5 * 60) api_help_getConfig(); if (!bind && this != Main.mtp) { final MTProto m = this; Common.logError("exportAuthorization"); Main.mtp.api( new TL.OnResultRPC() { @Override public void onResultRPC(TL.Object result, Object param, boolean error) { if (!error) return; if (result.id != 0xdf969c2d) return; // auth.ExportedAuthorization Common.logError("importAuthorization"); m.api( null, null, "auth.importAuthorization", result.getInt("id"), result.getBytes("bytes")); } }, null, "auth.exportAuthorization", dcState.getInt("id")); return; } if (bind) cb.onBind(); send_queue(); }
public static MTProto getConnection(int dc_id, MTProtoListener callback, int reuseFlag) { MTProto m = getActiveMTP(dc_id, reuseFlag); if (m != null) { Common.logError("reuse"); return m; } m = new MTProto(dc_id, callback, reuseFlag); mtp.add(m); return m; }
// MTProto public MTProto(int dc_id, MTProtoListener callback, int reuseFlag) { this.reuseFlag = reuseFlag; cb = callback; for (int i = 0; i < dcStates.size(); i++) if (dcStates.get(i).getInt("id") == dc_id) { dcState = dcStates.get(i); // Common.hexStringToByteArray("23D03699CE2AB29BA2273084D95DA126EC3A1D55BE4C317615CE66609D5562BDC0EFDE5AE1F9185001C35781F622B31DF5294685559340DE7D5CC8D7F6F86AE049107D8E498EB2AC3D6FA735DF90648EEC34A6B7BE3A5075A455F5696DB39280BF68C1637E1580E1EBA3F0C12EF2C03B8E9B5ECCFD3E4885BF636863388E3EC9E9EF60C722FF9B45CD93FA5E8D0D277B45A6A9370860582A159187F2F352D418D195D8E9310B5559E170F51CB2056F6CB6DB586E9349192A1B7EAA50887C115A14F996F5A855E90E47635A81EA3048615F4FD91347D73335E5503179857D0D29132483271B28E6591172C3D94686BD96E91FDB7AD9591A526218B3DDFC7A2A09") setAuthKey(dcState.getBytes("auth_key")); bind = dcState.getBool("bind"); seqno = dcState.getInt("seqno"); session = dcState.getLong("session"); server_salt = dcState.getLong("server_salt"); Common.logError("session: " + session + " seqno: " + seqno); connected = false; Thread netThread = new Thread(transport = new TransportTCP(this, true)); netThread.setPriority(Thread.MIN_PRIORITY); netThread.start(); return; } Common.logError("dc not found: " + dc_id); }
public void setTyping(int chat_id, boolean isTyping) { Common.logError(getTitle() + " is typing " + isTyping); if (typing != isTyping) { typing = isTyping; if (typing) { typing_time = Common.getUnixTime() + 6; typing_chat_id = chat_id; } ; Dialog dialog = chat_id != -1 ? Dialog.getDialog(-1, chat_id, true) : Dialog.getDialog(id, -1, true); Main.main.updateDialogItem(dialog); Main.main.updateUser(this); } }
public void invoke(String name, TL.Object obj) { Method m; try { m = MTProto.class.getDeclaredMethod("TL_" + name.replace(".", "_"), TL.Object.class); m.setAccessible(true); } catch (Exception e) { Common.logWarning("not handled: Main::" + name); return; } try { Common.logInfo("invoke: Main::" + name); m.invoke(this, obj); } catch (Exception e) { Common.logError("invoke error in Main"); e.printStackTrace(); } }
private void process(TL.Object obj) { // if (obj instanceof TL.Vector) // return; Method m; try { m = MTProto.class.getDeclaredMethod("TL_" + obj.type.replace(".", "_"), TL.Object.class); m.setAccessible(true); } catch (Exception e) { Common.logWarning("not handled: " + obj.type + " (" + obj.name + ")"); return; } try { Common.logInfo("invoke: " + obj.type + " (" + obj.name + ")"); m.invoke(this, obj); } catch (Exception e) { Common.logError("process error"); e.printStackTrace(); } }
public void TL_messages_Dialogs(TL.Object obj) { User.addUsers(obj.getVector("users")); Chat.addChats(obj.getVector("chats")); // dialogs TL.Vector dialogs = obj.getVector("dialogs"); for (int i = 0; i < dialogs.count; i++) { TL.Object dobj = dialogs.getObject(i); Dialog d = Dialog.getDialog(-1, dobj.getObject("peer"), true); d.updating = true; } // messages TL.Vector messages = obj.getVector("messages"); for (int i = 0; i < messages.count; i++) cb.onMessage(messages.getObject(i), Dialog.MSG_HISTORY); for (int i = 0; i < dialogs.count; i++) { TL.Object dobj = dialogs.getObject(i); Dialog d = Dialog.getDialog(-1, dobj.getObject("peer"), true); if (dobj.getInt("top_message") == -7) // config_dialogs magic d.noHistory = true; d.unread_count = dobj.getInt("unread_count"); d.updating = false; Main.main.updateDialog(d); } Common.logError("dialogs: " + Dialog.dialogs.size()); // slice if (obj.name.equals("messages.dialogsSlice") && dialogs.count > 0) { int limit = obj.getInt("count") - Dialog.dialogs.size(); if (limit > 0) api_messages_getDialogs(Dialog.dialogs.size(), 0, limit); } if (Main.main != null) Main.main.resetDialogs(); }
private void TL_ResPQ(TL.Object obj) { sv_nonce = obj.getBytes("server_nonce"); BigInteger pq = new BigInteger(1, obj.getBytes("pq")); TL.Vector v_fp = obj.getVector("server_public_key_fingerprints"); fp = v_fp.getLong(0); Common.logError("pq: " + pq.toString()); // prime factorization for pq BigInteger q = Common.rho(pq); BigInteger p = pq.divide(q); if (p.compareTo(q) > 0) { BigInteger t = p; p = q; q = t; } SecureRandom rnd = new SecureRandom(); new_nonce = new byte[32]; rnd.nextBytes(new_nonce); // generate encrypted_data TL.Object data_obj = TL.newObject("p_q_inner_data", pq, p, q, cl_nonce, sv_nonce, new_nonce); byte[] data = data_obj.serialize(); byte[] hash = Common.getSHA1(data); byte[] data_with_hash = new byte[255]; System.arraycopy(hash, 0, data_with_hash, 0, hash.length); System.arraycopy(data, 0, data_with_hash, hash.length, data.length); GEN_random_bytes(data_with_hash, data.length + hash.length, 255); byte[] encrypted_data = Common.RSA(RSA_MODULUS, RSA_EXPONENT, data_with_hash); // req_DH_params TL.Object req_obj = TL.newObject("req_DH_params", cl_nonce, sv_nonce, p, q, fp, encrypted_data); send(req_obj, false, false); }
public synchronized boolean sendMessage(Message msg) { if (msg == null) return false; if (!connected || (msg.encrypted && (auth_key == null || auth_key.length == 0)) || bad_seq) { Common.logError("add to queue " + connected + " " + msg.encrypted); TLMessageQueue.add(msg); return false; } ByteBuffer b = null; Common.logInfo("message send: " + msg.obj.name + ":" + msg.obj.type); byte[] msg_data = msg.obj.serialize(); /* if (msg_data.length > 255) { Common.logError("compress..."); byte[] data = Common.gzipDeflate(msg_data); // TODO: compress message data if (data.length < msg_data.length && data.length > 32) msg_data = TL.newObject("gzip_packed", data).serialize(); } */ if (msg.encrypted) { long message_id = GEN_message_id(); TLMessage.put(message_id, msg); int size_real = 32 + msg_data.length; int size_padding = (size_real + 15) / 16 * 16; ByteBuffer p = BufferAlloc(size_padding); p.putLong(server_salt); p.putLong(session); p.putLong(message_id); if (msg.accept) seqno++; p.putInt(seqno); if (msg.accept) seqno++; p.putInt(msg_data.length); p.put(msg_data); byte[] data = p.array(); GEN_random_bytes(data, p.position(), data.length); // encrypt data byte[] msg_key = Common.ASUB(Common.getSHA1(Common.ASUB(data, 0, size_real)), 4, 16); synchronized (aes) { aes.prepare(true, msg_key, auth_key); data = aes.IGE(data, true); } // write encrypted packet b = BufferAlloc(24 + data.length); b.putLong(auth_key_id); b.put(msg_key); b.put(data); } else { b = BufferAlloc(20 + msg_data.length); b.putLong(0); b.putLong(GEN_message_id()); b.putInt(msg_data.length); b.put(msg_data); } try { synchronized (transport) { transport.send(b.array()); return true; } } catch (Exception e) { return false; } }
public void api_messages_getDialogs(int offset, int max_id, int limit) { Common.logError("get dialogs: " + offset + " " + max_id + " " + limit); api(null, null, "messages.getDialogs", offset, max_id, limit); }
public void api_messages_getHistory( TL.Object peer, int offset, int max_id, int limit, TL.OnResultRPC result) { Common.logError("get history " + offset + " " + max_id + " " + limit); api(result, limit, "messages.getHistory", peer, offset, max_id, limit); }
public void getPhoto(ImageView img) { final TL.Object location = getPhotoLocation(); img.setTag(location); if (location == null) { img.setImageResource(getDefPhoto()); return; } String path = FileQuery.exists(location); if (path != null) { Bitmap bmp = BitmapCache.get(path); if (bmp != null) { img.setImageBitmap(bmp); return; } } final WeakReference<ImageView> ref = new WeakReference<ImageView>(img); try { new FileQuery( location, null, new FileQuery.OnResultListener() { @Override public void onResult(TL.Object result) { ImageView img = ref.get(); if (img == null || img.getTag() != location) return; final Bitmap bmp = result != null ? BitmapCache.loadBitmap( result.getString("fileName"), Main.SIZE_THUMB_USER, Main.SIZE_THUMB_USER, true, false, true) : BitmapFactory.decodeResource(Main.main.getResources(), getDefPhoto()); try { img.post( new Runnable() { @Override public void run() { ImageView img = ref.get(); if (img == null || img.getTag() != location) return; img.setImageBitmap(bmp); } }); } catch (Exception e) { Common.logError("error loading bitmap"); e.printStackTrace(); } } @Override public void onProgress(float progress) {} }); } catch (Exception e) { Common.logError("error query file"); e.printStackTrace(); } }
public void auth() { Common.logError("auth"); TL.Object req_pq = TL.newObject("req_pq", cl_nonce = GEN_random_bytes(16)); send(req_pq, false, false); }