1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 package org.drinkless.tdlib.example;
8 
9 import org.drinkless.tdlib.Client;
10 import org.drinkless.tdlib.TdApi;
11 
12 import java.io.IOError;
13 import java.io.IOException;
14 import java.io.BufferedReader;
15 import java.io.InputStreamReader;
16 import java.util.NavigableSet;
17 import java.util.TreeSet;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.locks.Condition;
21 import java.util.concurrent.locks.Lock;
22 import java.util.concurrent.locks.ReentrantLock;
23 
24 /**
25  * Example class for TDLib usage from Java.
26  */
27 public final class Example {
28     private static Client client = null;
29 
30     private static TdApi.AuthorizationState authorizationState = null;
31     private static volatile boolean haveAuthorization = false;
32     private static volatile boolean needQuit = false;
33     private static volatile boolean canQuit = false;
34 
35     private static final Client.ResultHandler defaultHandler = new DefaultHandler();
36 
37     private static final Lock authorizationLock = new ReentrantLock();
38     private static final Condition gotAuthorization = authorizationLock.newCondition();
39 
40     private static final ConcurrentMap<Long, TdApi.User> users = new ConcurrentHashMap<Long, TdApi.User>();
41     private static final ConcurrentMap<Long, TdApi.BasicGroup> basicGroups = new ConcurrentHashMap<Long, TdApi.BasicGroup>();
42     private static final ConcurrentMap<Long, TdApi.Supergroup> supergroups = new ConcurrentHashMap<Long, TdApi.Supergroup>();
43     private static final ConcurrentMap<Integer, TdApi.SecretChat> secretChats = new ConcurrentHashMap<Integer, TdApi.SecretChat>();
44 
45     private static final ConcurrentMap<Long, TdApi.Chat> chats = new ConcurrentHashMap<Long, TdApi.Chat>();
46     private static final NavigableSet<OrderedChat> mainChatList = new TreeSet<OrderedChat>();
47     private static boolean haveFullMainChatList = false;
48 
49     private static final ConcurrentMap<Long, TdApi.UserFullInfo> usersFullInfo = new ConcurrentHashMap<Long, TdApi.UserFullInfo>();
50     private static final ConcurrentMap<Long, TdApi.BasicGroupFullInfo> basicGroupsFullInfo = new ConcurrentHashMap<Long, TdApi.BasicGroupFullInfo>();
51     private static final ConcurrentMap<Long, TdApi.SupergroupFullInfo> supergroupsFullInfo = new ConcurrentHashMap<Long, TdApi.SupergroupFullInfo>();
52 
53     private static final String newLine = System.getProperty("line.separator");
54     private static final String commandsLine = "Enter command (gcs - GetChats, gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, q - Quit): ";
55     private static volatile String currentPrompt = null;
56 
57     static {
58         try {
59             System.loadLibrary("tdjni");
60         } catch (UnsatisfiedLinkError e) {
61             e.printStackTrace();
62         }
63     }
64 
print(String str)65     private static void print(String str) {
66         if (currentPrompt != null) {
67             System.out.println("");
68         }
69         System.out.println(str);
70         if (currentPrompt != null) {
71             System.out.print(currentPrompt);
72         }
73     }
74 
setChatPositions(TdApi.Chat chat, TdApi.ChatPosition[] positions)75     private static void setChatPositions(TdApi.Chat chat, TdApi.ChatPosition[] positions) {
76         synchronized (mainChatList) {
77             synchronized (chat) {
78                 for (TdApi.ChatPosition position : chat.positions) {
79                     if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
80                         boolean isRemoved = mainChatList.remove(new OrderedChat(chat.id, position));
81                         assert isRemoved;
82                     }
83                 }
84 
85                 chat.positions = positions;
86 
87                 for (TdApi.ChatPosition position : chat.positions) {
88                     if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
89                         boolean isAdded = mainChatList.add(new OrderedChat(chat.id, position));
90                         assert isAdded;
91                     }
92                 }
93             }
94         }
95     }
96 
onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState)97     private static void onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState) {
98         if (authorizationState != null) {
99             Example.authorizationState = authorizationState;
100         }
101         switch (Example.authorizationState.getConstructor()) {
102             case TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR:
103                 TdApi.TdlibParameters parameters = new TdApi.TdlibParameters();
104                 parameters.databaseDirectory = "tdlib";
105                 parameters.useMessageDatabase = true;
106                 parameters.useSecretChats = true;
107                 parameters.apiId = 94575;
108                 parameters.apiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
109                 parameters.systemLanguageCode = "en";
110                 parameters.deviceModel = "Desktop";
111                 parameters.applicationVersion = "1.0";
112                 parameters.enableStorageOptimizer = true;
113 
114                 client.send(new TdApi.SetTdlibParameters(parameters), new AuthorizationRequestHandler());
115                 break;
116             case TdApi.AuthorizationStateWaitEncryptionKey.CONSTRUCTOR:
117                 client.send(new TdApi.CheckDatabaseEncryptionKey(), new AuthorizationRequestHandler());
118                 break;
119             case TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR: {
120                 String phoneNumber = promptString("Please enter phone number: ");
121                 client.send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, null), new AuthorizationRequestHandler());
122                 break;
123             }
124             case TdApi.AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR: {
125                 String link = ((TdApi.AuthorizationStateWaitOtherDeviceConfirmation) Example.authorizationState).link;
126                 System.out.println("Please confirm this login link on another device: " + link);
127                 break;
128             }
129             case TdApi.AuthorizationStateWaitCode.CONSTRUCTOR: {
130                 String code = promptString("Please enter authentication code: ");
131                 client.send(new TdApi.CheckAuthenticationCode(code), new AuthorizationRequestHandler());
132                 break;
133             }
134             case TdApi.AuthorizationStateWaitRegistration.CONSTRUCTOR: {
135                 String firstName = promptString("Please enter your first name: ");
136                 String lastName = promptString("Please enter your last name: ");
137                 client.send(new TdApi.RegisterUser(firstName, lastName), new AuthorizationRequestHandler());
138                 break;
139             }
140             case TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR: {
141                 String password = promptString("Please enter password: ");
142                 client.send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
143                 break;
144             }
145             case TdApi.AuthorizationStateReady.CONSTRUCTOR:
146                 haveAuthorization = true;
147                 authorizationLock.lock();
148                 try {
149                     gotAuthorization.signal();
150                 } finally {
151                     authorizationLock.unlock();
152                 }
153                 break;
154             case TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR:
155                 haveAuthorization = false;
156                 print("Logging out");
157                 break;
158             case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
159                 haveAuthorization = false;
160                 print("Closing");
161                 break;
162             case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
163                 print("Closed");
164                 if (!needQuit) {
165                     client = Client.create(new UpdateHandler(), null, null); // recreate client after previous has closed
166                 } else {
167                     canQuit = true;
168                 }
169                 break;
170             default:
171                 System.err.println("Unsupported authorization state:" + newLine + Example.authorizationState);
172         }
173     }
174 
toInt(String arg)175     private static int toInt(String arg) {
176         int result = 0;
177         try {
178             result = Integer.parseInt(arg);
179         } catch (NumberFormatException ignored) {
180         }
181         return result;
182     }
183 
getChatId(String arg)184     private static long getChatId(String arg) {
185         long chatId = 0;
186         try {
187             chatId = Long.parseLong(arg);
188         } catch (NumberFormatException ignored) {
189         }
190         return chatId;
191     }
192 
promptString(String prompt)193     private static String promptString(String prompt) {
194         System.out.print(prompt);
195         currentPrompt = prompt;
196         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
197         String str = "";
198         try {
199             str = reader.readLine();
200         } catch (IOException e) {
201             e.printStackTrace();
202         }
203         currentPrompt = null;
204         return str;
205     }
206 
getCommand()207     private static void getCommand() {
208         String command = promptString(commandsLine);
209         String[] commands = command.split(" ", 2);
210         try {
211             switch (commands[0]) {
212                 case "gcs": {
213                     int limit = 20;
214                     if (commands.length > 1) {
215                         limit = toInt(commands[1]);
216                     }
217                     getMainChatList(limit);
218                     break;
219                 }
220                 case "gc":
221                     client.send(new TdApi.GetChat(getChatId(commands[1])), defaultHandler);
222                     break;
223                 case "me":
224                     client.send(new TdApi.GetMe(), defaultHandler);
225                     break;
226                 case "sm": {
227                     String[] args = commands[1].split(" ", 2);
228                     sendMessage(getChatId(args[0]), args[1]);
229                     break;
230                 }
231                 case "lo":
232                     haveAuthorization = false;
233                     client.send(new TdApi.LogOut(), defaultHandler);
234                     break;
235                 case "q":
236                     needQuit = true;
237                     haveAuthorization = false;
238                     client.send(new TdApi.Close(), defaultHandler);
239                     break;
240                 default:
241                     System.err.println("Unsupported command: " + command);
242             }
243         } catch (ArrayIndexOutOfBoundsException e) {
244             print("Not enough arguments");
245         }
246     }
247 
getMainChatList(final int limit)248     private static void getMainChatList(final int limit) {
249         synchronized (mainChatList) {
250             if (!haveFullMainChatList && limit > mainChatList.size()) {
251                 // send GetChats request if there are some unknown chats and have not enough known chats
252                 client.send(new TdApi.LoadChats(new TdApi.ChatListMain(), limit - mainChatList.size()), new Client.ResultHandler() {
253                     @Override
254                     public void onResult(TdApi.Object object) {
255                         switch (object.getConstructor()) {
256                             case TdApi.Error.CONSTRUCTOR:
257                                 if (((TdApi.Error) object).code == 404) {
258                                     synchronized (mainChatList) {
259                                         haveFullMainChatList = true;
260                                     }
261                                 } else {
262                                     System.err.println("Receive an error for GetChats:" + newLine + object);
263                                 }
264                                 break;
265                             case TdApi.Ok.CONSTRUCTOR:
266                                 // chats had already been received through updates, let's retry request
267                                 getMainChatList(limit);
268                                 break;
269                             default:
270                                 System.err.println("Receive wrong response from TDLib:" + newLine + object);
271                         }
272                     }
273                 });
274                 return;
275             }
276 
277             java.util.Iterator<OrderedChat> iter = mainChatList.iterator();
278             System.out.println();
279             System.out.println("First " + limit + " chat(s) out of " + mainChatList.size() + " known chat(s):");
280             for (int i = 0; i < limit && i < mainChatList.size(); i++) {
281                 long chatId = iter.next().chatId;
282                 TdApi.Chat chat = chats.get(chatId);
283                 synchronized (chat) {
284                     System.out.println(chatId + ": " + chat.title);
285                 }
286             }
287             print("");
288         }
289     }
290 
sendMessage(long chatId, String message)291     private static void sendMessage(long chatId, String message) {
292         // initialize reply markup just for testing
293         TdApi.InlineKeyboardButton[] row = {new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl())};
294         TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row});
295 
296         TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
297         client.send(new TdApi.SendMessage(chatId, 0, 0, null, replyMarkup, content), defaultHandler);
298     }
299 
main(String[] args)300     public static void main(String[] args) throws InterruptedException {
301         // disable TDLib log
302         Client.execute(new TdApi.SetLogVerbosityLevel(0));
303         if (Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false))) instanceof TdApi.Error) {
304             throw new IOError(new IOException("Write access to the current directory is required"));
305         }
306 
307         // create client
308         client = Client.create(new UpdateHandler(), null, null);
309 
310         // test Client.execute
311         defaultHandler.onResult(Client.execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));
312 
313         // main loop
314         while (!needQuit) {
315             // await authorization
316             authorizationLock.lock();
317             try {
318                 while (!haveAuthorization) {
319                     gotAuthorization.await();
320                 }
321             } finally {
322                 authorizationLock.unlock();
323             }
324 
325             while (haveAuthorization) {
326                 getCommand();
327             }
328         }
329         while (!canQuit) {
330             Thread.sleep(1);
331         }
332     }
333 
334     private static class OrderedChat implements Comparable<OrderedChat> {
335         final long chatId;
336         final TdApi.ChatPosition position;
337 
OrderedChat(long chatId, TdApi.ChatPosition position)338         OrderedChat(long chatId, TdApi.ChatPosition position) {
339             this.chatId = chatId;
340             this.position = position;
341         }
342 
343         @Override
compareTo(OrderedChat o)344         public int compareTo(OrderedChat o) {
345             if (this.position.order != o.position.order) {
346                 return o.position.order < this.position.order ? -1 : 1;
347             }
348             if (this.chatId != o.chatId) {
349                 return o.chatId < this.chatId ? -1 : 1;
350             }
351             return 0;
352         }
353 
354         @Override
equals(Object obj)355         public boolean equals(Object obj) {
356             OrderedChat o = (OrderedChat) obj;
357             return this.chatId == o.chatId && this.position.order == o.position.order;
358         }
359     }
360 
361     private static class DefaultHandler implements Client.ResultHandler {
362         @Override
onResult(TdApi.Object object)363         public void onResult(TdApi.Object object) {
364             print(object.toString());
365         }
366     }
367 
368     private static class UpdateHandler implements Client.ResultHandler {
369         @Override
onResult(TdApi.Object object)370         public void onResult(TdApi.Object object) {
371             switch (object.getConstructor()) {
372                 case TdApi.UpdateAuthorizationState.CONSTRUCTOR:
373                     onAuthorizationStateUpdated(((TdApi.UpdateAuthorizationState) object).authorizationState);
374                     break;
375 
376                 case TdApi.UpdateUser.CONSTRUCTOR:
377                     TdApi.UpdateUser updateUser = (TdApi.UpdateUser) object;
378                     users.put(updateUser.user.id, updateUser.user);
379                     break;
380                 case TdApi.UpdateUserStatus.CONSTRUCTOR:  {
381                     TdApi.UpdateUserStatus updateUserStatus = (TdApi.UpdateUserStatus) object;
382                     TdApi.User user = users.get(updateUserStatus.userId);
383                     synchronized (user) {
384                         user.status = updateUserStatus.status;
385                     }
386                     break;
387                 }
388                 case TdApi.UpdateBasicGroup.CONSTRUCTOR:
389                     TdApi.UpdateBasicGroup updateBasicGroup = (TdApi.UpdateBasicGroup) object;
390                     basicGroups.put(updateBasicGroup.basicGroup.id, updateBasicGroup.basicGroup);
391                     break;
392                 case TdApi.UpdateSupergroup.CONSTRUCTOR:
393                     TdApi.UpdateSupergroup updateSupergroup = (TdApi.UpdateSupergroup) object;
394                     supergroups.put(updateSupergroup.supergroup.id, updateSupergroup.supergroup);
395                     break;
396                 case TdApi.UpdateSecretChat.CONSTRUCTOR:
397                     TdApi.UpdateSecretChat updateSecretChat = (TdApi.UpdateSecretChat) object;
398                     secretChats.put(updateSecretChat.secretChat.id, updateSecretChat.secretChat);
399                     break;
400 
401                 case TdApi.UpdateNewChat.CONSTRUCTOR: {
402                     TdApi.UpdateNewChat updateNewChat = (TdApi.UpdateNewChat) object;
403                     TdApi.Chat chat = updateNewChat.chat;
404                     synchronized (chat) {
405                         chats.put(chat.id, chat);
406 
407                         TdApi.ChatPosition[] positions = chat.positions;
408                         chat.positions = new TdApi.ChatPosition[0];
409                         setChatPositions(chat, positions);
410                     }
411                     break;
412                 }
413                 case TdApi.UpdateChatTitle.CONSTRUCTOR: {
414                     TdApi.UpdateChatTitle updateChat = (TdApi.UpdateChatTitle) object;
415                     TdApi.Chat chat = chats.get(updateChat.chatId);
416                     synchronized (chat) {
417                         chat.title = updateChat.title;
418                     }
419                     break;
420                 }
421                 case TdApi.UpdateChatPhoto.CONSTRUCTOR: {
422                     TdApi.UpdateChatPhoto updateChat = (TdApi.UpdateChatPhoto) object;
423                     TdApi.Chat chat = chats.get(updateChat.chatId);
424                     synchronized (chat) {
425                         chat.photo = updateChat.photo;
426                     }
427                     break;
428                 }
429                 case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
430                     TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
431                     TdApi.Chat chat = chats.get(updateChat.chatId);
432                     synchronized (chat) {
433                         chat.lastMessage = updateChat.lastMessage;
434                         setChatPositions(chat, updateChat.positions);
435                     }
436                     break;
437                 }
438                 case TdApi.UpdateChatPosition.CONSTRUCTOR: {
439                     TdApi.UpdateChatPosition updateChat = (TdApi.UpdateChatPosition) object;
440                     if (updateChat.position.list.getConstructor() != TdApi.ChatListMain.CONSTRUCTOR) {
441                       break;
442                     }
443 
444                     TdApi.Chat chat = chats.get(updateChat.chatId);
445                     synchronized (chat) {
446                         int i;
447                         for (i = 0; i < chat.positions.length; i++) {
448                             if (chat.positions[i].list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
449                                 break;
450                             }
451                         }
452                         TdApi.ChatPosition[] new_positions = new TdApi.ChatPosition[chat.positions.length + (updateChat.position.order == 0 ? 0 : 1) - (i < chat.positions.length ? 1 : 0)];
453                         int pos = 0;
454                         if (updateChat.position.order != 0) {
455                           new_positions[pos++] = updateChat.position;
456                         }
457                         for (int j = 0; j < chat.positions.length; j++) {
458                             if (j != i) {
459                                 new_positions[pos++] = chat.positions[j];
460                             }
461                         }
462                         assert pos == new_positions.length;
463 
464                         setChatPositions(chat, new_positions);
465                     }
466                     break;
467                 }
468                 case TdApi.UpdateChatReadInbox.CONSTRUCTOR: {
469                     TdApi.UpdateChatReadInbox updateChat = (TdApi.UpdateChatReadInbox) object;
470                     TdApi.Chat chat = chats.get(updateChat.chatId);
471                     synchronized (chat) {
472                         chat.lastReadInboxMessageId = updateChat.lastReadInboxMessageId;
473                         chat.unreadCount = updateChat.unreadCount;
474                     }
475                     break;
476                 }
477                 case TdApi.UpdateChatReadOutbox.CONSTRUCTOR: {
478                     TdApi.UpdateChatReadOutbox updateChat = (TdApi.UpdateChatReadOutbox) object;
479                     TdApi.Chat chat = chats.get(updateChat.chatId);
480                     synchronized (chat) {
481                         chat.lastReadOutboxMessageId = updateChat.lastReadOutboxMessageId;
482                     }
483                     break;
484                 }
485                 case TdApi.UpdateChatUnreadMentionCount.CONSTRUCTOR: {
486                     TdApi.UpdateChatUnreadMentionCount updateChat = (TdApi.UpdateChatUnreadMentionCount) object;
487                     TdApi.Chat chat = chats.get(updateChat.chatId);
488                     synchronized (chat) {
489                         chat.unreadMentionCount = updateChat.unreadMentionCount;
490                     }
491                     break;
492                 }
493                 case TdApi.UpdateMessageMentionRead.CONSTRUCTOR: {
494                     TdApi.UpdateMessageMentionRead updateChat = (TdApi.UpdateMessageMentionRead) object;
495                     TdApi.Chat chat = chats.get(updateChat.chatId);
496                     synchronized (chat) {
497                         chat.unreadMentionCount = updateChat.unreadMentionCount;
498                     }
499                     break;
500                 }
501                 case TdApi.UpdateChatReplyMarkup.CONSTRUCTOR: {
502                     TdApi.UpdateChatReplyMarkup updateChat = (TdApi.UpdateChatReplyMarkup) object;
503                     TdApi.Chat chat = chats.get(updateChat.chatId);
504                     synchronized (chat) {
505                         chat.replyMarkupMessageId = updateChat.replyMarkupMessageId;
506                     }
507                     break;
508                 }
509                 case TdApi.UpdateChatDraftMessage.CONSTRUCTOR: {
510                     TdApi.UpdateChatDraftMessage updateChat = (TdApi.UpdateChatDraftMessage) object;
511                     TdApi.Chat chat = chats.get(updateChat.chatId);
512                     synchronized (chat) {
513                         chat.draftMessage = updateChat.draftMessage;
514                         setChatPositions(chat, updateChat.positions);
515                     }
516                     break;
517                 }
518                 case TdApi.UpdateChatPermissions.CONSTRUCTOR: {
519                     TdApi.UpdateChatPermissions update = (TdApi.UpdateChatPermissions) object;
520                     TdApi.Chat chat = chats.get(update.chatId);
521                     synchronized (chat) {
522                         chat.permissions = update.permissions;
523                     }
524                     break;
525                 }
526                 case TdApi.UpdateChatNotificationSettings.CONSTRUCTOR: {
527                     TdApi.UpdateChatNotificationSettings update = (TdApi.UpdateChatNotificationSettings) object;
528                     TdApi.Chat chat = chats.get(update.chatId);
529                     synchronized (chat) {
530                         chat.notificationSettings = update.notificationSettings;
531                     }
532                     break;
533                 }
534                 case TdApi.UpdateChatDefaultDisableNotification.CONSTRUCTOR: {
535                     TdApi.UpdateChatDefaultDisableNotification update = (TdApi.UpdateChatDefaultDisableNotification) object;
536                     TdApi.Chat chat = chats.get(update.chatId);
537                     synchronized (chat) {
538                         chat.defaultDisableNotification = update.defaultDisableNotification;
539                     }
540                     break;
541                 }
542                 case TdApi.UpdateChatIsMarkedAsUnread.CONSTRUCTOR: {
543                     TdApi.UpdateChatIsMarkedAsUnread update = (TdApi.UpdateChatIsMarkedAsUnread) object;
544                     TdApi.Chat chat = chats.get(update.chatId);
545                     synchronized (chat) {
546                         chat.isMarkedAsUnread = update.isMarkedAsUnread;
547                     }
548                     break;
549                 }
550                 case TdApi.UpdateChatIsBlocked.CONSTRUCTOR: {
551                     TdApi.UpdateChatIsBlocked update = (TdApi.UpdateChatIsBlocked) object;
552                     TdApi.Chat chat = chats.get(update.chatId);
553                     synchronized (chat) {
554                         chat.isBlocked = update.isBlocked;
555                     }
556                     break;
557                 }
558                 case TdApi.UpdateChatHasScheduledMessages.CONSTRUCTOR: {
559                     TdApi.UpdateChatHasScheduledMessages update = (TdApi.UpdateChatHasScheduledMessages) object;
560                     TdApi.Chat chat = chats.get(update.chatId);
561                     synchronized (chat) {
562                         chat.hasScheduledMessages = update.hasScheduledMessages;
563                     }
564                     break;
565                 }
566 
567                 case TdApi.UpdateUserFullInfo.CONSTRUCTOR:
568                     TdApi.UpdateUserFullInfo updateUserFullInfo = (TdApi.UpdateUserFullInfo) object;
569                     usersFullInfo.put(updateUserFullInfo.userId, updateUserFullInfo.userFullInfo);
570                     break;
571                 case TdApi.UpdateBasicGroupFullInfo.CONSTRUCTOR:
572                     TdApi.UpdateBasicGroupFullInfo updateBasicGroupFullInfo = (TdApi.UpdateBasicGroupFullInfo) object;
573                     basicGroupsFullInfo.put(updateBasicGroupFullInfo.basicGroupId, updateBasicGroupFullInfo.basicGroupFullInfo);
574                     break;
575                 case TdApi.UpdateSupergroupFullInfo.CONSTRUCTOR:
576                     TdApi.UpdateSupergroupFullInfo updateSupergroupFullInfo = (TdApi.UpdateSupergroupFullInfo) object;
577                     supergroupsFullInfo.put(updateSupergroupFullInfo.supergroupId, updateSupergroupFullInfo.supergroupFullInfo);
578                     break;
579                 default:
580                     // print("Unsupported update:" + newLine + object);
581             }
582         }
583     }
584 
585     private static class AuthorizationRequestHandler implements Client.ResultHandler {
586         @Override
onResult(TdApi.Object object)587         public void onResult(TdApi.Object object) {
588             switch (object.getConstructor()) {
589                 case TdApi.Error.CONSTRUCTOR:
590                     System.err.println("Receive an error:" + newLine + object);
591                     onAuthorizationStateUpdated(null); // repeat last action
592                     break;
593                 case TdApi.Ok.CONSTRUCTOR:
594                     // result is already received through UpdateAuthorizationState, nothing to do
595                     break;
596                 default:
597                     System.err.println("Receive wrong response from TDLib:" + newLine + object);
598             }
599         }
600     }
601 }