diff --git a/.gitmodules b/.gitmodules index 8ca1e77c..1c7c9e98 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "tgl"] path = tgl - url = https://github.com/vysheng/tgl + url = https://github.com/majn/tgl diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d9aec56..2284cf5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,25 @@ Changelog --------- +#### Version 1.2.0 (Beta 3) + +##### Bugfixes + + - Fix error in incoming message handling that caused segmentation faults + - Fix failing audio and video transfers + - Mark messages read on other devices as 'deferred' to avoid needless notifications + - Improved buddy list handling (should avoid "unknown" contacts popping up) + - Many small issues (see commit history) + - Fix issues that caused audio and video downloads to not have a proper file ending + - Fix issue that caused very old unused chats to not be available + +###### Features + + - Allow creation of new group chats + - Allow joining chats by invite link + - Allow exporting chats by invite link + - Support displaying and sending GIFs + - Support joining chats by invite link ##### Version 1.1.0 (Beta 2) diff --git a/README.md b/README.md index b290bf4c..bed291fb 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,34 @@ -Telegram-Purple (Beta) -=============== +Telegram-Purple Unofficial (Beta 3) +=================================== Telegram-purple is a Libpurple plugin that adds support for the Telegram messenger. +I keep getting many questions about this plugin in my mail, so I've created a telegram group +chat for [telegram group chat](https://telegram.me/joinchat/01fb53f301b67d3c7a5532908dfa9a89) +telegram-purple related discussions or questions. -Beta 2 +Beta 3 ------ - - update to libtgl 2 - - support two-factor authentication - - improve sticker support - - add option to control message read recipes - - many bugfixes +##### Bugfixes + - Fix error in incoming message handling that caused segmentation faults + - Fix failing audio and video transfers + - Improved buddy list handling (should avoid "unknown" contacts popping up) + - Many small issues (see commit history) + - Fix issues that caused audio and video downloads to not have a proper file ending + - Fix issue that caused very old unused chats to not be available + +###### Features + + - Support creation of new group chats + - Support joining chats by invite link + - Support exporting chats by invite link + - Support displaying and sending GIFs + - Mark messages read on other devices as 'deferred' to avoid needless notifications + + +This version should fix the crashes that seem to occur in many of the older version. Consider this another intermediate Beta version, there will be at least another one until I will consider it a release candidate. If you migrate from an older version, the Telegram authentication files have been moved to .purple/telegram-purple. If you want to keep your old secret chats, please copy it manually from ~/.telegram-purple, otherwise you will be prompted for a new SMS code. @@ -73,6 +89,14 @@ Usage The username is your current phone number, including your full country prefix. For Germany, this would be '+49', resulting in a user name like '+49151123456'. Telegram will verify your phone number by sending you a code via sms. You will be prompted for this code, once that happens. +#### Buddy List + +Like in the official Telegram apps, the displayed buddy list consists of all active conversations. + +##### Foreign Users + +Foreign users, like for example people you only know through a group chat but never had any conversation with, will not be part of your buddy list by default. You can add those users to the buddy list by clicking on "Add contact..." in the users context menu. + #### Using secret chats You can use Telegram secret chats with this plugin, they will show up as a new buddy with a '!' in front of the buddy name. @@ -89,7 +113,7 @@ Click on the buddy in the buddy list and click on "Show Info" to visualize the k ##### Initiate secret chats -To initiate a secret chat from Pidgin, click on a Buddy in the Buddy List and hit ``Start Secret Chat'' +To initiate a secret chat from Pidgin, click on a Buddy in the Buddy List and hit "Start Secret Chat" ##### Deleting secret chats @@ -102,20 +126,6 @@ The Telegram phone applications for iOS and Android make use of standardized Uni does not display those smileys natively, but you can install a custom smiley theme like (https://github.com/stv0g/unicode-emoji) or (https://github.com/VxJasonxV/emoji-for-pidgin) and activate it under Settings > Themes > Smiley Theme. -Troubleshooting ---------------- - -If you encounter problems running this plugin and you have updated from an older version, -deleting your old user-data might be helpful. WARNING: This will require you to enter a new authentication -code and delete all your secret chat keys. - -To clean all your user files run: - - - make purge - - - Building the Adium Plugin ------------------------- @@ -131,6 +141,15 @@ Compiling with XCode is a little bit problematic, since it requries you to compi 5. Build the XCode-Project and execute the created bundle + +Discussion / Help +----------------- + +Telegram group chat for telegram-purple or libtgl related discussions or questions: + + - https://telegram.me/joinchat/01fb53f301b67d3c7a5532908dfa9a89 + + Authors ------- diff --git a/configure b/configure index bcd06302..406faf86 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for telegram-purple 1.1.0. +# Generated by GNU Autoconf 2.69 for telegram-purple 1.2.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='telegram-purple' PACKAGE_TARNAME='telegram-purple' -PACKAGE_VERSION='1.1.0' -PACKAGE_STRING='telegram-purple 1.1.0' +PACKAGE_VERSION='1.2.0' +PACKAGE_STRING='telegram-purple 1.2.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1242,7 +1242,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures telegram-purple 1.1.0 to adapt to many kinds of systems. +\`configure' configures telegram-purple 1.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1303,7 +1303,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of telegram-purple 1.1.0:";; + short | recursive ) echo "Configuration of telegram-purple 1.2.0:";; esac cat <<\_ACEOF @@ -1406,7 +1406,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -telegram-purple configure 1.1.0 +telegram-purple configure 1.2.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1825,7 +1825,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by telegram-purple $as_me 1.1.0, which was +It was created by telegram-purple $as_me 1.2.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4902,7 +4902,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by telegram-purple $as_me 1.1.0, which was +This file was extended by telegram-purple $as_me 1.2.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4964,7 +4964,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -telegram-purple config.status 1.1.0 +telegram-purple config.status 1.2.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index c21003fc..6311e1e5 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([telegram-purple], [1.1.0]) +AC_INIT([telegram-purple], [1.2.0]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) diff --git a/rpm/purple-telegram.spec b/rpm/purple-telegram.spec index a120ec9c..be2d0731 100644 --- a/rpm/purple-telegram.spec +++ b/rpm/purple-telegram.spec @@ -1,14 +1,14 @@ Name: purple-telegram -Version: 1.0.1 +Version: 1.2.0 Release: 1%{?dist} -Summary: Adds support for Telegram to Pidgin, Adium, Finch and other Libpurple based messengers +Summary: Adds support for Telegram to Pidgin, Adium, Finch and other Libpurple based messengers. Group: Internet/Messaging License: GPLv2+ URL: https://github.com/majn/telegram-purple Source0: https://codeload.github.com/majn/telegram-purple/tar.gz/v%{version}.tar.gz -BuildRequires: openssl-devel,glib2-devel,libpurple-devel -Requires: openssl,glib2,libpurple +BuildRequires: openssl-devel,glib2-devel,libpurple-devel,libwebp-devel +Requires: openssl,glib2,libpurple,libwebp %description diff --git a/telegram-adium/TelegramAccount.m b/telegram-adium/TelegramAccount.m index 747e3c06..763b19ab 100644 --- a/telegram-adium/TelegramAccount.m +++ b/telegram-adium/TelegramAccount.m @@ -17,10 +17,19 @@ */ #import "TelegramAccount.h" +#import "tgp-ft.h" + #import #import #import -#import "tgp-ft.h" +#import +#import +#import + +#import +#import +#import + #include "telegram-purple.h" @@ -46,7 +55,6 @@ - (int)port return 443; } - - (void)configurePurpleAccount { [super configurePurpleAccount]; @@ -87,6 +95,41 @@ - (void)configurePurpleAccount intValue]); } +#pragma mark Action Menu +-(NSMenu*)actionMenuForChat:(AIChat*)chat +{ + NSArray *listObjects = nil; + AIListObject *listObject = nil; + + if (listObjects.count) { + listObject = [listObjects objectAtIndex:0]; + } + + NSMenu *menu = [adium.menuController + contextualMenuWithLocations: [NSArray arrayWithObjects: + [NSNumber numberWithInteger: Context_GroupChat_Manage], + [NSNumber numberWithInteger: Context_Group_Manage], + [NSNumber numberWithInteger: Context_GroupChat_Action], + nil] forChat: chat]; + + [menu addItem:[NSMenuItem separatorItem]]; + + [menu addItemWithTitle:@"Invite users by link..." + target:self + action:@selector(addUserByLink) + keyEquivalent:@"" + tag:0]; + return menu; +} +- (void)addUserByLink +{ + connection_data *conn = purple_connection_get_protocol_data (purple_account_get_connection(account)); + AIChat *chat = adium.interfaceController.activeChat; + const char *subject = [[[chat chatCreationDictionary] objectForKey:@"subject"] UTF8String]; + export_chat_link_checked (conn->TLS, subject); +} + +#pragma mark File transfer - (BOOL)canSendOfflineMessageToContact:(AIListContact *)inContact { return YES; diff --git a/telegram-adium/TelegramAccountView.xib b/telegram-adium/TelegramAccountView.xib index e510fff1..8f846a4d 100644 --- a/telegram-adium/TelegramAccountView.xib +++ b/telegram-adium/TelegramAccountView.xib @@ -1,5 +1,5 @@ - + diff --git a/telegram-adium/TelegramAccountViewController.m b/telegram-adium/TelegramAccountViewController.m index 4efb68ec..c2826c96 100644 --- a/telegram-adium/TelegramAccountViewController.m +++ b/telegram-adium/TelegramAccountViewController.m @@ -22,7 +22,7 @@ #import #import #import -#import DISPLAY +#import #include "telegram-purple.h" diff --git a/telegram-adium/TelegramAutocompletionDelegate.h b/telegram-adium/TelegramAutocompletionDelegate.h new file mode 100644 index 00000000..87b216a4 --- /dev/null +++ b/telegram-adium/TelegramAutocompletionDelegate.h @@ -0,0 +1,28 @@ +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * + * Copyright Matthias Jentsch 2014-2015 + */ + +#import + +#include + +@interface TelegramAutocompletionDelegate : NSObject { + @private + struct tgl_state *TLS; +} +- (void)setTLS:(struct tgl_state *)TLS; +@end \ No newline at end of file diff --git a/telegram-adium/TelegramAutocompletionDelegate.m b/telegram-adium/TelegramAutocompletionDelegate.m new file mode 100644 index 00000000..3e74adac --- /dev/null +++ b/telegram-adium/TelegramAutocompletionDelegate.m @@ -0,0 +1,62 @@ +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * + * Copyright Matthias Jentsch 2014-2015 + */ + +#import + +#import "TelegramAutocompletionDelegate.h" + +@implementation TelegramAutocompletionDelegate + +- (NSArray *)tokenField:(NSTokenField *)tokenField +completionsForSubstring:(NSString *)substring + indexOfToken:(NSInteger)tokenIndex + indexOfSelectedItem:(NSInteger *)selectedIndex +{ + NSMutableArray *matchingUsers = [NSMutableArray new]; + const char *startsWith = [substring UTF8String]; + if (TLS) { + int i = 0; + while (i != -1) { + char *R = NULL; + i = tgl_complete_user_list (TLS, i, startsWith, (int) strlen(startsWith), &R); + if (R) { + [matchingUsers addObject: [[NSString alloc] initWithUTF8String:R]]; + } + } + } + return matchingUsers; +} + +- (id)tokenField:(NSTokenField *)tokenField +representedObjectForEditingString:(NSString *)editingString +{ + return nil; +} + +- (NSString *)tokenField:(NSTokenField *)tokenField +displayStringForRepresentedObject:(id)representedObject +{ + return nil; +} + +- (void)setTLS:(struct tgl_state *)_TLS +{ + TLS = _TLS; +} + +@end \ No newline at end of file diff --git a/telegram-adium/TelegramJoinChatView.xib b/telegram-adium/TelegramJoinChatView.xib index c1bf91c7..281ce266 100644 --- a/telegram-adium/TelegramJoinChatView.xib +++ b/telegram-adium/TelegramJoinChatView.xib @@ -1,24 +1,27 @@ - + - + + + + - + - + @@ -26,15 +29,91 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + diff --git a/telegram-adium/TelegramJoinChatViewController.h b/telegram-adium/TelegramJoinChatViewController.h index 9b0e3889..eefbc11a 100644 --- a/telegram-adium/TelegramJoinChatViewController.h +++ b/telegram-adium/TelegramJoinChatViewController.h @@ -20,8 +20,11 @@ @class AIAccount, AICompletingTextField; -@interface TelegramJoinChatViewController : DCJoinChatViewController { +@interface TelegramJoinChatViewController : DCJoinChatViewController { IBOutlet NSPopUpButton *popupButton_existingChat; + IBOutlet NSTextField *textField_joinByLink; + IBOutlet NSTextField *textField_createChatName; + IBOutlet NSTokenField *tokenField_createChatUsers; } @end \ No newline at end of file diff --git a/telegram-adium/TelegramJoinChatViewController.m b/telegram-adium/TelegramJoinChatViewController.m index 72baffc3..2419094b 100644 --- a/telegram-adium/TelegramJoinChatViewController.m +++ b/telegram-adium/TelegramJoinChatViewController.m @@ -17,10 +17,13 @@ */ #include -#include "TelegramJoinChatViewController.h" #include "telegram-purple.h" #include "tgp-structs.h" #include "tgp-chat.h" +#include "telegram-base.h" + +#include "TelegramJoinChatViewController.h" +#include "TelegramAutocompletionDelegate.h" #import #import @@ -67,32 +70,59 @@ - (void)configureForAccount:(AIAccount *)inAccount [leftChats addObject: name]; } } - + NSArray *sortedChats = [chats sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { return [(NSString*)a compare:b options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch]; }]; [popupButton_existingChat addItemsWithTitles: sortedChats]; - // TODO: Display left chats with a grey font to indicate that those are no // longer, but still allow the user to view the history // [popupButton_existingChat addItemsWithTitles: leftChats]; + + // provide the current TLS instance for access by the autocompletion + TelegramAutocompletionDelegate *D = [tokenField_createChatUsers delegate]; + if (D != nil) { + [D setTLS:conn->TLS]; + } } } - (void)joinChatWithAccount:(AIAccount *)inAccount { - NSString *room = [[popupButton_existingChat selectedItem] title]; - - NSDictionary *chatCreationInfo = [NSDictionary - dictionaryWithObjectsAndKeys:room, @"subject", nil]; - - [self doJoinChatWithName:room - onAccount:inAccount - chatCreationInfo:chatCreationInfo - invitingContacts:@[] - withInvitationMessage:@""]; + PurpleAccount *pa = [(CBPurpleAccount *)inAccount purpleAccount]; + PurpleConnection *gc = purple_account_get_connection(pa); + if (gc && PURPLE_CONNECTION_IS_CONNECTED(gc)) { + connection_data *conn = purple_connection_get_protocol_data (gc); + NSString *link = [textField_joinByLink stringValue]; + + if ([link length]) { + import_chat_link_checked (conn->TLS, [link UTF8String]); + return; + } + NSString *createChatName = [textField_createChatName stringValue]; + NSArray *tokens = [tokenField_createChatUsers objectValue]; + if ([createChatName length] && [tokens count]) { + int i, cnt = (int)[tokens count]; + const char **users = g_malloc(cnt * sizeof(char*)); + for (i = 0; i < cnt; i++) { + users[i] = [tokens[i] UTF8String]; + } + tgp_create_group_chat_by_usernames (conn->TLS, [createChatName UTF8String], users, i, TRUE); + g_free (users); + return; + } + + NSString *room = [[popupButton_existingChat selectedItem] title]; + NSDictionary *chatCreationInfo = [NSDictionary + dictionaryWithObjectsAndKeys:room, @"subject", nil]; + [self doJoinChatWithName:room + onAccount:inAccount + chatCreationInfo:chatCreationInfo + invitingContacts:@[] + withInvitationMessage:@""]; + } } - (NSString *)nibName @@ -100,5 +130,4 @@ - (NSString *)nibName return @"TelegramJoinChatView"; } - @end diff --git a/telegram-adium/TelegramPlugin.m b/telegram-adium/TelegramPlugin.m index e420bdef..478a5f80 100644 --- a/telegram-adium/TelegramPlugin.m +++ b/telegram-adium/TelegramPlugin.m @@ -31,9 +31,9 @@ @implementation TelegramPlugin - (void) installPlugin { - pk_path = [self getPkName]; - purple_init_telegram_plugin(); - [TelegramService registerService]; + pk_path = [self getPkName]; + purple_init_telegram_plugin(); + [TelegramService registerService]; } - (void) installLibpurplePlugin diff --git a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj index ed018ca8..39b851ec 100644 --- a/telegram-adium/telegram-adium.xcodeproj/project.pbxproj +++ b/telegram-adium/telegram-adium.xcodeproj/project.pbxproj @@ -44,18 +44,10 @@ C4D819061A5C862E0044CBA9 /* tgp-structs.c in Sources */ = {isa = PBXBuildFile; fileRef = C4D819041A5C862E0044CBA9 /* tgp-structs.c */; }; C4E528111A8A907200C4B915 /* tgp-ft.c in Sources */ = {isa = PBXBuildFile; fileRef = C4E5280F1A8A907200C4B915 /* tgp-ft.c */; }; C4EA965A1B204C67006CBAD0 /* libwebp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C4EA96591B204C67006CBAD0 /* libwebp.a */; }; + C4FFD0DC1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h in Sources */ = {isa = PBXBuildFile; fileRef = C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */; }; + C4FFD0DE1B5FC68400939D8A /* TelegramAutocompletionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - C4B57BF51B160EA6006997F4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = C410947E19BB2D7D0083BF3F /* Project object */; - proxyType = 1; - remoteGlobalIDString = C4B57BF11B160950006997F4; - remoteInfo = "telegram-purple"; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ C40564861A7937C600A293B9 /* AdiumLibpurple.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdiumLibpurple.framework; path = Frameworks/Adium/AdiumLibpurple.framework; sourceTree = ""; }; C410948619BB2D7D0083BF3F /* telegram-adium.AdiumLibpurplePlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "telegram-adium.AdiumLibpurplePlugin"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -122,6 +114,8 @@ C4E5280F1A8A907200C4B915 /* tgp-ft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tgp-ft.c"; path = "../tgp-ft.c"; sourceTree = ""; }; C4E528101A8A907200C4B915 /* tgp-ft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tgp-ft.h"; path = "../tgp-ft.h"; sourceTree = ""; }; C4EA96591B204C67006CBAD0 /* libwebp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebp.a; path = Frameworks/libwebp.a; sourceTree = ""; }; + C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TelegramAutocompletionDelegate.h; sourceTree = ""; }; + C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TelegramAutocompletionDelegate.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -149,6 +143,8 @@ C410947D19BB2D7D0083BF3F = { isa = PBXGroup; children = ( + C4FFD0DB1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h */, + C4FFD0DD1B5FC68400939D8A /* TelegramAutocompletionDelegate.m */, C4B4BE321AB4536F0064AC17 /* PurpleDefaultsTelegram.plist */, C438CE251A12BEAF00E1DA0F /* telegram22.png */, C438CE231A12BEAF00E1DA0F /* telegram.png */, @@ -276,23 +272,6 @@ }; /* End PBXGroup section */ -/* Begin PBXLegacyTarget section */ - C4B57BF11B160950006997F4 /* telegram-purple */ = { - isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION)"; - buildConfigurationList = C4B57BF21B160951006997F4 /* Build configuration list for PBXLegacyTarget "telegram-purple" */; - buildPhases = ( - ); - buildToolPath = /usr/bin/make; - buildWorkingDirectory = "$(PROJECT_DIR)/../"; - dependencies = ( - ); - name = "telegram-purple"; - passBuildSettingsInEnvironment = 0; - productName = "telegram-purple"; - }; -/* End PBXLegacyTarget section */ - /* Begin PBXNativeTarget section */ C410948519BB2D7D0083BF3F /* telegram-adium */ = { isa = PBXNativeTarget; @@ -305,7 +284,6 @@ buildRules = ( ); dependencies = ( - C4B57BF61B160EA6006997F4 /* PBXTargetDependency */, ); name = "telegram-adium"; productName = "telegram-adium"; @@ -320,11 +298,6 @@ attributes = { LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Matthias Jentsch"; - TargetAttributes = { - C4B57BF11B160950006997F4 = { - CreatedOnToolsVersion = 6.3.2; - }; - }; }; buildConfigurationList = C410948119BB2D7D0083BF3F /* Build configuration list for PBXProject "telegram-adium" */; compatibilityVersion = "Xcode 3.2"; @@ -339,7 +312,6 @@ projectRoot = ""; targets = ( C410948519BB2D7D0083BF3F /* telegram-adium */, - C4B57BF11B160950006997F4 /* telegram-purple */, ); }; /* End PBXProject section */ @@ -368,6 +340,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C4FFD0DC1B5FC48B00939D8A /* TelegramAutocompletionDelegate.h in Sources */, C438CE321A12C07800E1DA0F /* msglog.c in Sources */, C438CE351A12C07800E1DA0F /* tgp-net.c in Sources */, C438CE331A12C07800E1DA0F /* telegram-base.c in Sources */, @@ -375,6 +348,7 @@ C438CE341A12C07800E1DA0F /* telegram-purple.c in Sources */, C4877C1819BB37EA006FA91F /* TelegramService.m in Sources */, C448ADA71AB0789A001B7ECD /* tgp-msg.c in Sources */, + C4FFD0DE1B5FC68400939D8A /* TelegramAutocompletionDelegate.m in Sources */, C4E528111A8A907200C4B915 /* tgp-ft.c in Sources */, C438CE361A12C07800E1DA0F /* tgp-timers.c in Sources */, C410949B19BB337A0083BF3F /* TelegramPlugin.m in Sources */, @@ -390,14 +364,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - C4B57BF61B160EA6006997F4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = C4B57BF11B160950006997F4 /* telegram-purple */; - targetProxy = C4B57BF51B160EA6006997F4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ C410948E19BB2D7D0083BF3F /* InfoPlist.strings */ = { isa = PBXVariantGroup; @@ -567,44 +533,6 @@ }; name = Release; }; - C4B57BF31B160951006997F4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_UNREACHABLE_CODE = YES; - DEBUGGING_SYMBOLS = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = YES; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Debug; - }; - C4B57BF41B160951006997F4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_WARN_UNREACHABLE_CODE = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; - MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -626,15 +554,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; - C4B57BF21B160951006997F4 /* Build configuration list for PBXLegacyTarget "telegram-purple" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - C4B57BF31B160951006997F4 /* Debug */, - C4B57BF41B160951006997F4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Debug; - }; /* End XCConfigurationList section */ }; rootObject = C410947E19BB2D7D0083BF3F /* Project object */; diff --git a/telegram-base.c b/telegram-base.c index 621554ae..a369d438 100644 --- a/telegram-base.c +++ b/telegram-base.c @@ -40,6 +40,7 @@ #include "tgp-2prpl.h" #include "tgp-structs.h" #include "tgp-utils.h" +#include "tgp-chat.h" #include "lodepng/lodepng.h" #define _(m) m @@ -140,10 +141,10 @@ void write_dc (struct tgl_dc *DC, void *extra) { assert (DC->flags & TGLDCF_LOGGED_IN); - assert (write (auth_file_fd, &DC->port, 4) == 4); - int l = strlen (DC->ip); + assert (write (auth_file_fd, &DC->options[0]->port, 4) == 4); + int l = strlen (DC->options[0]->ip); assert (write (auth_file_fd, &l, 4) == 4); - assert (write (auth_file_fd, DC->ip, l) == l); + assert (write (auth_file_fd, DC->options[0]->ip, l) == l); assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8); assert (write (auth_file_fd, DC->auth_key, 256) == 256); } @@ -451,12 +452,16 @@ static void code_auth_receive_result (struct tgl_state *TLS, void *extra, int su } void request_code_entered (gpointer data, const gchar *code) { + char *stripped = g_strstrip (purple_markup_strip_html (code)); + struct tgl_state *TLS = data; connection_data *conn = TLS->ev_base; char const *username = purple_account_get_username(conn->pa); + debug ("sending code: '%s'\n", stripped); tgl_do_send_code_result (TLS, username, (int)strlen (username), conn->hash, - (int)strlen (conn->hash), code, (int)strlen (code), + (int)strlen (conn->hash), stripped, (int)strlen (stripped), code_receive_result, 0); + g_free (stripped); } static void request_code_canceled (gpointer data) { @@ -479,7 +484,6 @@ static void request_code (struct tgl_state *TLS) { // purple request API is not available, so we create a new conversation (the Telegram system // account "7770000") to prompt the user for the code - conn->in_fallback_chat = 1; purple_connection_set_state (conn->gc, PURPLE_CONNECTED); PurpleConversation *conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, conn->pa, "777000"); @@ -493,18 +497,20 @@ static void request_name_code_entered (PurpleConnection* gc, PurpleRequestFields struct tgl_state *TLS = conn->TLS; char const *username = purple_account_get_username(conn->pa); - const char* first = purple_request_fields_get_string(fields, "first_name"); - const char* last = purple_request_fields_get_string(fields, "last_name"); - const char* code = purple_request_fields_get_string(fields, "code"); + char* first = g_strstrip (g_strdup (purple_request_fields_get_string (fields, "first_name"))); + char* last = g_strstrip (g_strdup (purple_request_fields_get_string (fields, "last_name"))); + char* code = g_strstrip (g_strdup (purple_request_fields_get_string (fields, "code"))); if (!first || !last || !code) { request_name_and_code (TLS); return; } - - tgl_do_send_code_result_auth(TLS, username, (int)strlen(username), conn->hash, + tgl_do_send_code_result_auth (TLS, username, (int)strlen(username), conn->hash, (int)strlen (conn->hash), code, (int)strlen (code), first, (int)strlen (first), last, (int)strlen (last), code_auth_receive_result, NULL); + g_free (first); + g_free (last); + g_free (code); } static void request_name_and_code (struct tgl_state *TLS) { @@ -538,12 +544,12 @@ static void request_name_and_code (struct tgl_state *TLS) { static void request_password_entered (struct request_password_data *data, PurpleRequestFields* fields) { const char* pass = purple_request_fields_get_string (fields, "password"); - data->callback (data->TLS, pass, data->arg); + data->callback (data->TLS, &pass, data->arg); free (data); } void request_password (struct tgl_state *TLS, - void (*callback)(struct tgl_state *TLS, const char *string, void *arg), + void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg) { connection_data *conn = TLS->ev_base; @@ -571,8 +577,11 @@ void request_password (struct tgl_state *TLS, } } -void write_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *E) { - if (!success) { return; } +void write_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, struct tgl_secret_chat *_) { + if (!success) { + tgp_notify_on_error_gw (TLS, NULL, success); + return; + } write_secret_chat_file (TLS); } @@ -609,6 +618,111 @@ void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat * g_free (message); } +void create_group_chat_done_cb (struct tgl_state *TLS, void *title, int success) { + if (success) { + tgl_peer_t *t = tgl_peer_get_by_name(TLS, title); + if (t) { + connection_data *conn = TLS->ev_base; + chat_show (conn->gc, tgl_get_peer_id(t->id)); + } + } + tgp_notify_on_error_gw (TLS, NULL, success); + g_free (title); +} + +void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *title, + const char *users[], int num_users, int print_names) { + tgl_peer_id_t ids[num_users + 1]; + int i, j = 0; + ids[j++] = TGL_MK_USER(TLS->our_id); + for (i = 0; i < num_users; i++) if (str_not_empty(users[i])) { + tgl_peer_t *P = NULL; + if (print_names) { + P = tgl_peer_get_by_name (TLS, users[i]); + } else { + P = tgl_peer_get (TLS, TGL_MK_USER(atoi (users[i]))); + } + if (P && tgl_get_peer_id (P->id) != TLS->our_id) { + ids[j++] = P->id; + } else { + debug("User %s not found in peer list", users[j]); + } + } + if (i > 0) { + tgl_do_create_group_chat (TLS, i + 1, ids, title, (int) strlen(title), + create_group_chat_done_cb, g_strdup (title)); + } else { + purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_INFO, + "Group not created", "Not enough users selected", + NULL, NULL, NULL); + } +} + +static void create_group_chat_cb (void *_data, PurpleRequestFields* fields) { + debug ("create_group_chat_cb()"); + struct accept_create_chat_data *data = _data; + const char *users[3] = { + purple_request_fields_get_string(fields, "user1"), + purple_request_fields_get_string(fields, "user2"), + purple_request_fields_get_string(fields, "user3") + }; + + tgp_create_group_chat_by_usernames (data->TLS, data->title, users, 3, FALSE); + g_free (data->title); + free (data); +} + +static void cancel_group_chat_cb (gpointer data) { + debug ("cancel_group_chat_cb()"); + + struct accept_create_chat_data *d = data; + g_free (d->title); + free (d); +} + +void request_choose_user (struct accept_create_chat_data *data) { + struct tgl_state *TLS = data->TLS; + connection_data *conn = TLS->ev_base; + + // Telegram doesn't allow to create chats with only one user, so we need to force + // the user to specify at least one other one. + PurpleRequestFields* fields = purple_request_fields_new(); + PurpleRequestFieldGroup* group = purple_request_field_group_new ( + "Use the autocompletion to invite at least one additional user. You can always add more users once the chat was created..."); + + PurpleRequestField *field = purple_request_field_string_new("user1", "User Name", NULL, FALSE); + purple_request_field_set_type_hint (field, "screenname"); + purple_request_field_group_add_field (group, field); + + field = purple_request_field_string_new("user2", "User Name", NULL, FALSE); + purple_request_field_set_type_hint (field, "screenname"); + purple_request_field_group_add_field (group, field); + + field = purple_request_field_string_new("user3", "User Name", NULL, FALSE); + purple_request_field_set_type_hint (field, "screenname"); + purple_request_field_group_add_field (group, field); + + purple_request_fields_add_group(fields, group); + purple_request_fields (conn->gc, "Create Group", "Invite Users", NULL, fields, + "Ok", G_CALLBACK(create_group_chat_cb), "Cancel", + G_CALLBACK(cancel_group_chat_cb), conn->pa, NULL, NULL, data); +} + +void request_create_chat (struct tgl_state *TLS, const char *subject) { + connection_data *conn = TLS->ev_base; + + struct accept_create_chat_data *data = malloc(sizeof(struct accept_create_chat_data)); + data->title = g_strdup(subject); + data->TLS = TLS; + + char *title = g_strdup_printf ("Chat doesn't exist, create a new group chat named '%s'?", subject); + purple_request_accept_cancel (conn->gc, "Create New Group Chat", title, NULL, 1, + conn->pa, NULL, NULL, data, + G_CALLBACK(request_choose_user), + G_CALLBACK(cancel_group_chat_cb)); + g_free (title); +} + static void sign_in_callback (struct tgl_state *TLS, void *extra, int success, int registered, const char *mhash) { connection_data *conn = TLS->ev_base; if (!error_if_val_false (TLS, success, "Invalid phone number", @@ -721,3 +835,13 @@ int tgp_visualize_key (struct tgl_state *TLS, unsigned char* sha1_key) { g_free(image); return imgStoreId; } + +void tgp_notify_on_error_gw (struct tgl_state *TLS, void *extra, int success) { + if (!success) { + char *errormsg = g_strdup_printf ("%d: %s", TLS->error_code, TLS->error); + failure (errormsg); + purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, "Query Failed", + errormsg, NULL, NULL, NULL); + return; + } +} diff --git a/telegram-base.h b/telegram-base.h index 53155efd..68e2c19b 100644 --- a/telegram-base.h +++ b/telegram-base.h @@ -24,7 +24,7 @@ struct request_password_data { struct tgl_state *TLS; - void (*callback)(struct tgl_state *TLS, const char *string, void *arg); + void (*callback)(struct tgl_state *TLS, const char *string[], void *arg); void *arg; }; @@ -39,14 +39,19 @@ void write_secret_chat_gw (struct tgl_state *TLS, void *extra, int success, stru void telegram_login (struct tgl_state *TLS); void request_code_entered (gpointer data, const gchar *code); -void request_password (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, const char *string, void *arg), void *arg); - +void request_password (struct tgl_state *TLS, void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), + void *arg); void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *U); +void request_create_chat (struct tgl_state *TLS, const char *subject); + gchar *get_config_dir (struct tgl_state *TLS, char const *username); gchar *get_download_dir (struct tgl_state *TLS); void assert_file_exists (PurpleConnection *gc, const char *filepath, const char *format); int tgp_visualize_key(struct tgl_state *TLS, unsigned char* sha1_key); +void tgp_create_group_chat_by_usernames (struct tgl_state *TLS, const char *title, + const char *users[], int num_users, int print_names); +void tgp_notify_on_error_gw (struct tgl_state *TLS, void *extra, int success); #endif diff --git a/telegram-purple.c b/telegram-purple.c index 8d7167ea..5f4afa8f 100755 --- a/telegram-purple.c +++ b/telegram-purple.c @@ -72,8 +72,9 @@ #include "tgp-ft.h" #include "tgp-msg.h" -static void get_password (struct tgl_state *TLS, const char *prompt, int flags, void (*callback)(struct tgl_state *TLS, const char *string, void *arg), void *arg); -static void update_message_received (struct tgl_state *TLS, struct tgl_message *M); +static void get_password (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, + void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg); +static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M); static void update_user_handler (struct tgl_state *TLS, struct tgl_user *U, unsigned flags); static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U); static void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *C, unsigned flags); @@ -81,6 +82,8 @@ static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status); static void update_marked_read (struct tgl_state *TLS, int num, struct tgl_message *list[]); static char *format_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); +void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, struct tgl_user *U); +void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); PurpleGroup *tggroup; const char *config_dir = "telegram-purple"; @@ -88,9 +91,9 @@ const char *pk_path = "/etc/telegram-purple/server.pub"; struct tgl_update_callback tgp_callback = { .logprintf = debug, - .get_string = get_password, - .new_msg = update_message_received, - .msg_receive = update_message_received, + .get_values = get_password, + .new_msg = update_message_handler, + .msg_receive = update_message_handler, .user_update = update_user_handler, .user_status_update = update_user_status_handler, .chat_update = update_chat_handler, @@ -100,52 +103,62 @@ struct tgl_update_callback tgp_callback = { .create_print_name = format_print_name }; -static void update_message_received (struct tgl_state *TLS, struct tgl_message *M) { - write_files_schedule (TLS); - tgp_msg_recv (TLS, M); +static void _update_buddy (struct tgl_state *TLS, tgl_peer_t *user, unsigned flags) { + PurpleBuddy *buddy = p2tgl_buddy_find (TLS, user->id); + if (buddy) { + if (flags & TGL_UPDATE_DELETED) { + purple_blist_remove_buddy (buddy); + } else { + if (flags & (TGL_UPDATE_NAME | TGL_UPDATE_REAL_NAME | TGL_UPDATE_USERNAME)) { + char *alias = p2tgl_strdup_alias (user); + purple_blist_alias_buddy (buddy, alias); + g_free (alias); + } + if (flags & TGL_UPDATE_PHOTO) { + tgl_do_get_user_info (TLS, user->id, 0, on_user_get_info, get_user_info_data_new (0, user->id)); + } + } + } } -void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, struct tgl_user *U); static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, unsigned flags) { - if (TLS->our_id == tgl_get_peer_id (user->id)) { - if (flags & TGL_UPDATE_NAME) { - p2tgl_connection_set_display_name (TLS, (tgl_peer_t *)user); - } + if (TLS->our_id == tgl_get_peer_id (user->id) && flags & TGL_UPDATE_NAME) { + p2tgl_connection_set_display_name (TLS, (tgl_peer_t *)user); + return; + } + + if (! (flags & TGL_UPDATE_CREATED)) { + // buddy was altered, update it + _update_buddy (TLS, (tgl_peer_t *)user, flags); } else { - PurpleBuddy *buddy = p2tgl_buddy_find (TLS, user->id); - if (!buddy) { - buddy = p2tgl_buddy_new (TLS, (tgl_peer_t *)user); - purple_blist_add_buddy (buddy, NULL, tggroup, NULL); - } - if (flags & TGL_UPDATE_CREATED) { - purple_buddy_set_protocol_data (buddy, (gpointer)user); + // new buddy was fetched, just update the status for all buddies in the contact list + if (p2tgl_buddy_find (TLS, user->id)) { p2tgl_prpl_got_user_status (TLS, user->id, &user->status); - p2tgl_buddy_update (TLS, (tgl_peer_t *)user, flags); - } - if (flags & TGL_UPDATE_PHOTO) { - tgl_do_get_user_info (TLS, user->id, 0, on_user_get_info, get_user_info_data_new (0, user->id)); - } - if (flags & TGL_UPDATE_DELETED && buddy) { - purple_blist_remove_buddy (buddy); } } } +static void update_message_handler (struct tgl_state *TLS, struct tgl_message *M) { + write_files_schedule (TLS); + tgp_msg_recv (TLS, M); + + if (M->flags & TGLMF_SERVICE && + (M->action.type == tgl_message_action_chat_add_user || + M->action.type == tgl_message_action_chat_delete_user)) { + tgl_do_get_chat_info (TLS, M->to_id, FALSE, on_chat_get_info, NULL); + } +} + static void update_user_status_handler (struct tgl_state *TLS, struct tgl_user *U) { p2tgl_prpl_got_user_status (TLS, U->id, &U->status); } static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret_chat *U, unsigned flags) { - debug ("secret-chat-state: %d", U->state); - - if (flags & TGL_UPDATE_WORKING || flags & TGL_UPDATE_DELETED) { - write_secret_chat_file (TLS); - } - PurpleBuddy *buddy = p2tgl_buddy_find (TLS, U->id); + debug ("update_secret_chat_handler: state=%d", U->state); - if (! (flags & TGL_UPDATE_DELETED)) { - if (!buddy) { + if (!(flags & TGL_UPDATE_DELETED)) { + if (! buddy) { buddy = p2tgl_buddy_new (TLS, (tgl_peer_t *)U); purple_blist_add_buddy (buddy, NULL, tggroup, NULL); purple_blist_alias_buddy (buddy, U->print_name); @@ -153,47 +166,49 @@ static void update_secret_chat_handler (struct tgl_state *TLS, struct tgl_secret p2tgl_prpl_got_set_status_mobile (TLS, U->id); } - if (flags & TGL_UPDATE_REQUESTED && buddy) { + if (flags & TGL_UPDATE_WORKING || flags & TGL_UPDATE_DELETED) { + write_secret_chat_file (TLS); + } + + if (flags & TGL_UPDATE_REQUESTED) { connection_data *conn = TLS->ev_base; const char* choice = purple_account_get_string (conn->pa, "accept-secret-chats", "ask"); if (! strcmp (choice, "always")) { tgl_do_accept_encr_chat_request (TLS, U, write_secret_chat_gw, 0); } else if (! strcmp(choice, "ask")) { - request_accept_secret_chat(TLS, U); + request_accept_secret_chat (TLS, U); } } - if (flags & TGL_UPDATE_CREATED && buddy) { - purple_buddy_set_protocol_data (buddy, (gpointer)U); - p2tgl_buddy_update (TLS, (tgl_peer_t *)U, flags); - } - - if (flags & TGL_UPDATE_DELETED && buddy) { - p2tgl_got_im (TLS, U->id, "Secret chat terminated.", PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_WHISPER, time(0)); - p2tgl_prpl_got_set_status_offline (TLS, U->id); + if (!(flags & TGL_UPDATE_CREATED) && buddy) { + if (flags & TGL_UPDATE_DELETED) { + p2tgl_got_im (TLS, U->id, "Secret chat terminated.", PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_WHISPER, time(0)); + p2tgl_prpl_got_set_status_offline (TLS, U->id); + } else { + _update_buddy (TLS, (tgl_peer_t *)U, flags); + } } } static void update_chat_handler (struct tgl_state *TLS, struct tgl_chat *chat, unsigned flags) { PurpleChat *ch = p2tgl_chat_find (TLS, chat->id); - if (flags & TGL_UPDATE_CREATED) { - tgl_do_get_chat_info (TLS, chat->id, 0, on_chat_get_info, 0); - } - if (flags & TGL_UPDATE_TITLE && ch) { - purple_blist_alias_chat (ch, chat->print_title); - } - if (flags & (TGL_UPDATE_MEMBERS | TGL_UPDATE_ADMIN) && ch) { - chat_users_update (TLS, chat); - } - if (flags & TGL_UPDATE_DELETED && ch) { - purple_blist_remove_chat (ch); + if (! (flags & TGL_UPDATE_CREATED)) { + if (flags & TGL_UPDATE_TITLE && ch) { + purple_blist_alias_chat (ch, chat->print_title); + } + if (flags & (TGL_UPDATE_MEMBERS | TGL_UPDATE_ADMIN) && ch) { + chat_users_update (TLS, chat); + } + if (flags & TGL_UPDATE_DELETED && ch) { + purple_blist_remove_chat (ch); + } } } static void update_user_typing (struct tgl_state *TLS, struct tgl_user *U, enum tgl_typing_status status) { if (status == tgl_typing_typing) { - p2tgl_got_typing(TLS, U->id, 2); + p2tgl_got_typing (TLS, U->id, 2); } } @@ -253,27 +268,30 @@ static char *format_print_name (struct tgl_state *TLS, tgl_peer_id_t id, const c return tgl_strdup (s); } -static void get_password (struct tgl_state *TLS, const char *prompt, int flags, - void (*callback)(struct tgl_state *TLS, const char *string, void *arg), void *arg) { - connection_data *conn = TLS->ev_base; - const char *P = purple_account_get_string (conn->pa, TGP_KEY_PASSWORD_TWO_FACTOR, NULL); - if (str_not_empty (P)) { - if (conn->password_retries++ < 1) { - callback (TLS, P, arg); - return; +static void get_password (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values, + void (*callback)(struct tgl_state *TLS, const char *string[], void *arg), void *arg) { + if (type == tgl_cur_password) { + connection_data *conn = TLS->ev_base; + const char *P = purple_account_get_string (conn->pa, TGP_KEY_PASSWORD_TWO_FACTOR, NULL); + + if (str_not_empty (P)) { + if (conn->password_retries++ < 1) { + callback (TLS, &P, arg); + return; + } } + request_password (TLS, callback, arg); } - request_password (TLS, callback, arg); } static void on_contact_added (struct tgl_state *TLS,void *callback_extra, int success, int size, struct tgl_user *users[]) { - PurpleBuddy *buddy = callback_extra; - - purple_blist_remove_buddy (buddy); if (!success || !size) { - + PurpleBuddy *buddy = callback_extra; + purple_blist_remove_buddy (buddy); purple_notify_error (_telegram_protocol, "Adding Buddy Failed", "Buddy Not Found", "No contact with this phone number was found."); + } else { + _update_buddy (TLS, (tgl_peer_t *)users[0], TGL_UPDATE_PHOTO | TGL_UPDATE_NAME); } } @@ -286,7 +304,10 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, if (!success || !P) { warning ("Can not load userpic for user %s %s", U->first_name, U->last_name); - goto fin; + tgp_notify_on_error_gw (TLS, NULL, success); + free (dld->get_user_info_data); + free (dld); + return; } int imgStoreId = p2tgl_imgstore_add_with_id (filename); @@ -294,24 +315,51 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, used_images_add (conn, imgStoreId); p2tgl_buddy_icons_set_for_user (conn->pa, &P->id, filename); - if (dld->get_user_info_data->show_info == 1) { PurpleNotifyUserInfo *info = p2tgl_notify_peer_info_new (TLS, P); p2tgl_notify_userinfo (TLS, P->id, info, NULL, NULL); } } -fin: free (dld->get_user_info_data); free (dld); } +static void on_get_dialog_list_done (struct tgl_state *TLS, void *callback_extra, int success, int size, tgl_peer_id_t peers[], int last_msg_id[], int unread_count[]) { + int i; + for (i = size - 1; i >= 0; i--) { + tgl_peer_t *UC; + switch (tgl_get_peer_type (peers[i])) { + + case TGL_PEER_USER: { + PurpleBuddy *buddy = p2tgl_buddy_find (TLS, peers[i]); + UC = tgl_peer_get (TLS, peers[i]); + if (tgl_get_peer_id (peers[i]) != TLS->our_id) { + if (! buddy) { + buddy = p2tgl_buddy_new (TLS, UC); + purple_blist_add_buddy (buddy, NULL, tggroup, NULL); + tgl_do_get_user_info (TLS, UC->id, 0, on_user_get_info, get_user_info_data_new (0, UC->id)); + } + p2tgl_prpl_got_user_status (TLS, UC->id, &UC->user.status); + p2tgl_prpl_got_set_status_mobile (TLS, UC->id); + } else { + p2tgl_connection_set_display_name (TLS, UC); + } + break; + } + + case TGL_PEER_CHAT: + tgl_do_get_chat_info (TLS, peers[i], FALSE, on_chat_get_info, NULL); + break; + } + } +} + void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, struct tgl_user *U) { get_user_info_data *user_info_data = (get_user_info_data *)info_data; tgl_peer_t *P = tgl_peer_get (TLS, user_info_data->peer); - if (! success) { - warning ("on_user_get_info not successfull, aborting..."); + tgp_notify_on_error_gw (TLS, NULL, success); return; } @@ -332,7 +380,8 @@ void on_user_get_info (struct tgl_state *TLS, void *info_data, int success, stru } void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C) { - if (!success || !chat_is_member (TLS->our_id, C)) { + if (!success) { + failure ("chat_get_info FAILED"); return; } @@ -359,9 +408,8 @@ void on_ready (struct tgl_state *TLS) { } debug ("seq = %d, pts = %d, date = %d", TLS->seq, TLS->pts, TLS->date); - tgl_do_get_difference (TLS, purple_account_get_bool (conn->pa, "history-sync-all", FALSE), - NULL, NULL); - tgl_do_get_dialog_list (TLS, 0, 0, NULL, NULL); + tgl_do_get_difference (TLS, purple_account_get_bool (conn->pa, "history-sync-all", FALSE), tgp_notify_on_error_gw, NULL); + tgl_do_get_dialog_list (TLS, 200, 0, on_get_dialog_list_done, NULL); tgl_do_update_contact_list (TLS, 0, 0); } @@ -370,19 +418,14 @@ static const char *tgprpl_list_icon (PurpleAccount * acct, PurpleBuddy * buddy) } static void tgprpl_tooltip_text (PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { - debug ("tgprpl_tooltip_text()", buddy->name); - - tgl_peer_id_t *peer = purple_buddy_get_protocol_data(buddy); - if (!peer) { - return; - } + debug ("tgprpl_tooltip_text()"); + assert (buddy->name); - tgl_peer_t *P = tgl_peer_get (get_conn_from_buddy (buddy)->TLS, *peer); + tgl_peer_t *P = find_peer_by_name (get_conn_from_buddy (buddy)->TLS, buddy->name); if (!P) { - warning ("Warning peer with id %d not found in tree.", peer->id); + warning ("Peer %s not found in tree.", buddy->name); return; } - gchar *status = tgp_format_user_status (&P->user.status); purple_notify_user_info_add_pair (info, "last online: ", status); g_free (status); @@ -415,37 +458,106 @@ static GList *tgprpl_status_types (PurpleAccount * acct) { return g_list_reverse (types); } +static void create_secret_chat_done (struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E) { + if (! success) { + tgp_notify_on_error_gw (TLS, NULL, success); + return; + } + write_secret_chat_file (TLS); +} + static void start_secret_chat (PurpleBlistNode *node, gpointer data) { PurpleBuddy *buddy = data; connection_data *conn = get_conn_from_buddy (buddy); const char *name = purple_buddy_get_name (buddy); - tgl_do_create_secret_chat (conn->TLS, TGL_MK_USER(atoi (name)), 0, 0); + tgl_do_create_secret_chat (conn->TLS, TGL_MK_USER(atoi (name)), create_secret_chat_done, 0); +} + +static void create_chat_link_done (struct tgl_state *TLS, void *extra, int success, const char *url) { + connection_data *conn = TLS->ev_base; + tgl_peer_t *C = extra; + + if (success) { + chat_show (conn->gc, tgl_get_peer_id (C->id)); + char *msg = g_strdup_printf("Invite link: %s", url); + serv_got_chat_in (conn->gc, tgl_get_peer_id(C->id), "WebPage", PURPLE_MESSAGE_SYSTEM, + msg, time(NULL)); + g_free (msg); + } else { + tgp_notify_on_error_gw (TLS, NULL, success); + } +} + +static void create_chat_link (PurpleBlistNode *node, gpointer data) { + PurpleChat *chat = (PurpleChat*)node; + connection_data *conn = purple_connection_get_protocol_data ( + purple_account_get_connection(purple_chat_get_account(chat))); + export_chat_link_checked (conn->TLS, purple_chat_get_name (chat)); +} + +void export_chat_link_checked (struct tgl_state *TLS, const char *name) { + tgl_peer_t *C = tgl_peer_get_by_name (TLS, name); + if (! C) { + failure ("Chat \"%s\" not found, not exporting link.", name); + return; + } + if (C->chat.admin_id != TLS->our_id) { + purple_notify_error (_telegram_protocol, "Failure", "Creating Chat Link Failed", + "You need to be admin of the group to do that."); + return; + } + tgl_do_export_chat_link (TLS, C->id, create_chat_link_done, C); +} + +static void import_chat_link_done (struct tgl_state *TLS, void *extra, int success) { + if (! success) { + tgp_notify_on_error_gw (TLS, NULL, success); + return; + } + purple_notify_info (_telegram_protocol, "Success", "Chat Joined", "Chat joined."); +} + +void import_chat_link_checked (struct tgl_state *TLS, const char *link) { + tgl_do_import_chat_link (TLS, link, (int) strlen(link), import_chat_link_done, NULL); } static GList* tgprpl_blist_node_menu (PurpleBlistNode *node) { debug ("tgprpl_blist_node_menu()"); - + GList* menu = NULL; if (PURPLE_BLIST_NODE_IS_BUDDY(node)) { // Add encrypted chat option to the right click menu of all buddies PurpleBuddy* buddy = (PurpleBuddy*)node; - PurpleMenuAction* menu_action = purple_menu_action_new("Start Secret Chat", + PurpleMenuAction* action = purple_menu_action_new ("Start secret chat", PURPLE_CALLBACK(start_secret_chat), buddy, NULL); - menu = g_list_append(menu, (gpointer)menu_action); + + menu = g_list_append(menu, (gpointer)action); + } + if (PURPLE_BLIST_NODE_IS_CHAT(node)) { + // Generate Public Link + PurpleMenuAction* action = purple_menu_action_new ("Invite users by link", + PURPLE_CALLBACK(create_chat_link), NULL, NULL); + menu = g_list_append(menu, (gpointer)action); } return menu; } static GList *tgprpl_chat_join_info (PurpleConnection * gc) { debug ("tgprpl_chat_join_info()"); - struct proto_chat_entry *pce; + struct proto_chat_entry *pce; pce = g_new0(struct proto_chat_entry, 1); pce->label = "_Subject:"; pce->identifier = "subject"; - pce->required = TRUE; - return g_list_append(NULL, pce); + pce->required = FALSE; + GList *info = g_list_append (NULL, pce); + + pce = g_new0(struct proto_chat_entry, 1); + pce->label = "_Join by Link:"; + pce->identifier = "link"; + pce->required = FALSE; + return g_list_append (info, pce); } static void tgprpl_login (PurpleAccount * acct) { @@ -491,6 +603,12 @@ static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *m // this is part of a workaround to support clients without // the request API (request.h), see telegram-base.c:request_code() if (conn->in_fallback_chat) { + + // OTR plugins may try to insert messages that don't contain the code + if (tgp_startswith (message, "?OTR")) { + info ("Fallback SMS auth, skipping OTR messsage: '%s'", message); + return -1; + } request_code_entered (conn->TLS, message); conn->in_fallback_chat = 0; return 1; @@ -562,7 +680,8 @@ static void tgprpl_set_status (PurpleAccount * acct, PurpleStatus * status) { if (!gc) { return; } connection_data *conn = purple_connection_get_protocol_data (gc); - if (p2tgl_status_is_present (status) && p2tgl_send_notifications (acct)) { + int present = p2tgl_status_is_present (status); + if (present && p2tgl_send_notifications (acct)) { pending_reads_send_all (conn->pending_reads, conn->TLS); } } @@ -570,10 +689,13 @@ static void tgprpl_set_status (PurpleAccount * acct, PurpleStatus * status) { static void tgprpl_add_buddy (PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) { connection_data *conn = purple_connection_get_protocol_data(gc); const char* first = buddy->alias ? buddy->alias : ""; + tgl_peer_t *peer = tgl_peer_get (conn->TLS, TGL_MK_USER (atoi (buddy->name))); - if (! tgl_peer_get (conn->TLS, TGL_MK_USER (atoi (buddy->name)))) { + if (! peer) { tgl_do_add_contact (conn->TLS, buddy->name, (int)strlen (buddy->name), first, (int)strlen (first), "", 0, 0, on_contact_added, buddy); + } else { + _update_buddy (conn->TLS, peer, TGL_UPDATE_NAME | TGL_UPDATE_PHOTO); } } @@ -596,15 +718,14 @@ static void tgprpl_remove_buddy (PurpleConnection * gc, PurpleBuddy * buddy, Pur bl_do_encr_chat_delete (conn->TLS, &peer->encr_chat); break; case TGL_PEER_USER: - tgl_do_del_contact (conn->TLS, peer->id, NULL, NULL); + tgl_do_del_contact (conn->TLS, peer->id, tgp_notify_on_error_gw, NULL); break; } - } static void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) { debug ("tgprpl_chat_join()"); - const char *subject = NULL; + const char *subject = NULL, *link = NULL; gpointer value; connection_data *conn = purple_connection_get_protocol_data (gc); @@ -614,14 +735,20 @@ static void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) { return; } - subject = g_hash_table_lookup(data, "subject"); + link = g_hash_table_lookup(data, "link"); + if (str_not_empty (link)) { + tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL); + return; + } + + subject = g_hash_table_lookup (data, "subject"); if (str_not_empty (subject)) { tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject); if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { chat_show (conn->gc, tgl_get_peer_id (P->id)); return; } - debug ("Peer with name %s not found or not a chat.", subject); + request_create_chat (conn->TLS, subject); } } @@ -629,9 +756,15 @@ static char *tgprpl_get_chat_name (GHashTable * data) { return g_strdup(g_hash_table_lookup(data, "subject")); } -static GHashTable *tgprpl_chat_info_deflt (PurpleConnection * gc, const char *chat_name) { - debug ("tgprpl_chat_info_defaults()"); - return NULL; +static void add_user_to_chat_done_cb (struct tgl_state *TLS, void *callback_extra, int success) { + tgl_peer_t *C = callback_extra; + + if (success) { + // update users + tgl_do_get_chat_info (TLS, C->id, FALSE, on_chat_get_info, NULL); + } else { + tgp_notify_on_error_gw (TLS, NULL, success); + } } static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *message, const char *name) { @@ -646,7 +779,7 @@ static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *messa return; } - tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, NULL, NULL); + tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, add_user_to_chat_done_cb, chat); } static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) { @@ -658,6 +791,7 @@ static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, return ret; } +/* static void tgprpl_set_buddy_icon (PurpleConnection * gc, PurpleStoredImage * img) { debug ("tgprpl_set_buddy_icon()"); @@ -666,11 +800,12 @@ static void tgprpl_set_buddy_icon (PurpleConnection * gc, PurpleStoredImage * im char* filename = g_strdup_printf ("%s/icons/%s", purple_user_dir(), purple_imgstore_get_filename (img)); debug (filename); - tgl_do_set_profile_photo (conn->TLS, filename, NULL, NULL); + tgl_do_set_profile_photo (conn->TLS, filename, tgp_notify_on_error_gw, NULL); g_free (filename); } } +*/ static gboolean tgprpl_can_receive_file (PurpleConnection * gc, const char *who) { return TRUE; @@ -680,7 +815,7 @@ PurplePlugin *_telegram_protocol = NULL; static PurplePluginProtocolInfo prpl_info = { OPT_PROTO_NO_PASSWORD | OPT_PROTO_IM_IMAGE, - NULL, // user_splits, initialized in tgprpl_init() + NULL, // user_¡splits, initialized in tgprpl_init() NULL, // protocol_options, initialized in tgprpl_init() { "png", @@ -698,7 +833,7 @@ static PurplePluginProtocolInfo prpl_info = { tgprpl_status_types, tgprpl_blist_node_menu, // blist_node_menu tgprpl_chat_join_info, - tgprpl_chat_info_deflt, + NULL, tgprpl_login, tgprpl_close, tgprpl_send_im, @@ -734,7 +869,7 @@ static PurplePluginProtocolInfo prpl_info = { NULL, // buddy_free NULL, // convo_closed NULL, // normalize - tgprpl_set_buddy_icon, + NULL, // tgprpl_set_buddy_icon NULL, // remove_group NULL, NULL, // set_chat_topic @@ -775,12 +910,14 @@ static void tgprpl_init (PurplePlugin *plugin) { } // Login - - opt = purple_account_option_string_new ("Password (two factor authentication)", + opt = purple_account_option_string_new ("Password (two factor authentication)", TGP_KEY_PASSWORD_TWO_FACTOR, NULL); + purple_account_option_set_masked (opt, TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); - opt = purple_account_option_bool_new("Fallback SMS Verification", "compat-verification", 0); + opt = purple_account_option_bool_new( + "Fallback SMS verification\n(Helps when not using Pidgin and you aren't being prompted for the code)", + "compat-verification", 0); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); diff --git a/telegram-purple.h b/telegram-purple.h index 942c8ba7..567d05fd 100644 --- a/telegram-purple.h +++ b/telegram-purple.h @@ -64,5 +64,7 @@ void on_ready (struct tgl_state *TLS); extern const char *pk_path; extern const char *config_dir; extern PurplePlugin *_telegram_protocol; +void export_chat_link_checked (struct tgl_state *TLS, const char *name); +void import_chat_link_checked (struct tgl_state *TLS, const char *link); #endif diff --git a/tgl b/tgl index 195b2bcc..126b42c6 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit 195b2bcccdefd63282654c4d827315a48b677f97 +Subproject commit 126b42c6d281841acc541735e845d94c54298f46 diff --git a/tgp-2prpl.c b/tgp-2prpl.c index ed8593b0..53597a4d 100644 --- a/tgp-2prpl.c +++ b/tgp-2prpl.c @@ -133,7 +133,7 @@ void p2tgl_got_alias (struct tgl_state *TLS, tgl_peer_id_t who, const char *alia void p2tgl_got_im (struct tgl_state *TLS, tgl_peer_id_t who, const char *msg, int flags, time_t when) { char *name = p2tgl_strdup_id(who); - serv_got_im(tg_get_conn(TLS), name, msg,flags, when); + serv_got_im(tg_get_conn(TLS), name, msg, flags, when); g_free (name); } @@ -232,19 +232,7 @@ PurpleBuddy *p2tgl_buddy_new (struct tgl_state *TLS, tgl_peer_t *user) { return b; } -PurpleBuddy *p2tgl_buddy_update (struct tgl_state *TLS, tgl_peer_t *user, unsigned flags) { - PurpleBuddy *b = p2tgl_buddy_find (TLS, user->id); - if (!b) { - b = p2tgl_buddy_new (TLS, user); - } - if (flags & (TGL_UPDATE_NAME | TGL_UPDATE_REAL_NAME | TGL_UPDATE_USERNAME)) { - debug ("Update username for id%d (name %s %s)", tgl_get_peer_id (user->id), user->user.first_name, user->user.last_name); - char *alias = p2tgl_strdup_alias (user); - purple_blist_alias_buddy(b, alias); - g_free (alias); - } - return b; -} + void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user) { char *name = p2tgl_strdup_id (user); @@ -322,7 +310,7 @@ void p2tgl_conv_add_user (PurpleConversation *conv, struct tgl_chat_user user, c PurpleConvChat *cdata = purple_conversation_get_chat_data(conv); char *name = g_strdup_printf("%d", user.user_id); - purple_conv_chat_add_user(cdata, name, message, flags, new_arrival); + purple_conv_chat_add_user (cdata, name, message, flags, new_arrival); g_free(name); } @@ -333,7 +321,6 @@ void p2tgl_connection_set_display_name(struct tgl_state *TLS, tgl_peer_t *user) g_free(name); } - void *p2tgl_notify_userinfo(struct tgl_state *TLS, tgl_peer_id_t user, PurpleNotifyUserInfo *user_info, PurpleNotifyCloseCallback cb, gpointer user_data) { char *name = p2tgl_strdup_id(user); void *handle = 0; @@ -402,7 +389,7 @@ PurpleNotifyUserInfo *p2tgl_notify_encrypted_chat_info_new (struct tgl_state *TL if (secret->first_key_sha[0]) { int sha1key_store_id = tgp_visualize_key (TLS, secret->first_key_sha); if (sha1key_store_id != -1) { - char *ident_icon = format_img_full (sha1key_store_id); + char *ident_icon = tgp_format_img (sha1key_store_id); purple_notify_user_info_add_pair (info, "Secret key", ident_icon); g_free(ident_icon); } diff --git a/tgp-2prpl.h b/tgp-2prpl.h index 0efdad01..fd8afe16 100644 --- a/tgp-2prpl.h +++ b/tgp-2prpl.h @@ -53,7 +53,6 @@ void p2tgl_got_typing (struct tgl_state *TLS, tgl_peer_id_t name, int timeout); PurpleBuddy *p2tgl_buddy_find (struct tgl_state *TLS, tgl_peer_id_t user); PurpleBuddy *p2tgl_buddy_new (struct tgl_state *TLS, tgl_peer_t *user); -PurpleBuddy *p2tgl_buddy_update (struct tgl_state *TLS, tgl_peer_t *user, unsigned flags); void p2tgl_buddy_add_data (struct tgl_state *TLS, tgl_peer_id_t user, void *data); void p2tgl_prpl_got_user_status (struct tgl_state *TLS, tgl_peer_id_t user, struct tgl_user_status *status); void p2tgl_prpl_got_set_status_mobile (struct tgl_state *TLS, tgl_peer_id_t user); diff --git a/tgp-chat.c b/tgp-chat.c index 21842cf0..ef917a50 100644 --- a/tgp-chat.c +++ b/tgp-chat.c @@ -58,7 +58,7 @@ PurpleConversation *chat_show (PurpleConnection *gc, int id) { int chat_is_member (int who, struct tgl_chat *chat) { int i; - for (i = 0; i < chat->user_list_size; i++) if ((chat->user_list + i)->user_id) { + for (i = 0; i < chat->user_list_size; i++) if ((chat->user_list + i)->user_id == who) { return TRUE; } return FALSE; diff --git a/tgp-ft.c b/tgp-ft.c index 13b8728e..ad07fd3b 100644 --- a/tgp-ft.c +++ b/tgp-ft.c @@ -27,6 +27,7 @@ #include #include #include "telegram-purple.h" +#include "telegram-base.h" static void tgprpl_xfer_free_data (struct tgp_xfer_send_data *data); @@ -35,12 +36,20 @@ static char *tgp_strdup_determine_filename (const char *mime, const char *captio if (caption) { return g_strdup (caption); } - const char *type = NULL; if (mime) { - type = tgp_mime_to_filetype (mime); + if (flags & TGLDF_VIDEO) { + // video message + type = "mp4"; + } else if (flags & TGLDF_AUDIO) { + // audio message + type = "ogg"; + } else { + // document message + type = tgp_mime_to_filetype (mime); + } } - if (!type) { + if (! str_not_empty(type)) { if (flags & TGLDF_IMAGE) { type = "png"; } else if (flags & TGLDF_AUDIO) { @@ -72,6 +81,7 @@ static void tgprpl_xfer_recv_on_finished (struct tgl_state *TLS, void *_data, in g_rename (filename, purple_xfer_get_local_filename (data->xfer)); } else { + tgp_notify_on_error_gw (TLS, NULL, success); failure ("ERROR xfer failed"); } @@ -90,7 +100,9 @@ static void tgprpl_xfer_on_finished (struct tgl_state *TLS, void *_data, int suc purple_xfer_set_completed (data->xfer, TRUE); purple_xfer_end(data->xfer); } + write_secret_chat_file (TLS); } else { + tgp_notify_on_error_gw (TLS, NULL, success); failure ("ERROR xfer failed"); } @@ -146,16 +158,36 @@ static gboolean tgprpl_xfer_upload_progress (gpointer _data) { static void tgprpl_xfer_recv_init (PurpleXfer *X) { debug ("tgprpl_xfer_recv_init"); struct tgp_xfer_send_data *data = X->data; + struct tgl_state *TLS = data->conn->TLS; + struct tgl_message *M = data->msg; + struct tgl_document *D = M->media.document; + tgl_peer_t *P = NULL; + purple_xfer_start (X, -1, NULL, 0); const char *who = purple_xfer_get_remote_user (X); - tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who); + P = find_peer_by_name (TLS, who); if (P) { - if (data->document) { - tgl_do_load_document (data->conn->TLS, data->document, tgprpl_xfer_recv_on_finished, data); - } - else if (data->encr_document) { - tgl_do_load_encr_document (data->conn->TLS, data->encr_document, - tgprpl_xfer_recv_on_finished, data); + switch (M->media.type) { + case tgl_message_media_document: + tgl_do_load_document (TLS, D, tgprpl_xfer_recv_on_finished, data); + break; + + case tgl_message_media_document_encr: + tgl_do_load_encr_document (TLS, M->media.encr_document, + tgprpl_xfer_recv_on_finished, data); + break; + + case tgl_message_media_audio: + tgl_do_load_audio (TLS, D, tgprpl_xfer_recv_on_finished, data); + break; + + case tgl_message_media_video: + tgl_do_load_video (TLS, D, tgprpl_xfer_recv_on_finished, data); + break; + + default: + failure ("Unknown message media type: %d, XFER not possible.", M->media.type); + break; } } else { warning ("User not found, not downloading..."); @@ -175,27 +207,19 @@ static void tgprpl_xfer_send_init (PurpleXfer *X) { tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who); if (P) { - if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { tgl_do_send_document (data->conn->TLS, P->id, (char*) localfile, NULL, 0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgprpl_xfer_on_finished, data); - } - else { - purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, "Not supported", - "Sorry, sending documents to encrypted chats not yet supported.", - NULL, NULL, NULL); - } } data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X); } -static void tgprpl_xfer_init_data (PurpleXfer *X, connection_data *conn, struct tgl_document *D, struct tgl_encr_document *ED) { +static void tgprpl_xfer_init_data (PurpleXfer *X, connection_data *conn, struct tgl_message *msg) { if (!X->data) { struct tgp_xfer_send_data *data = g_malloc0 (sizeof (struct tgp_xfer_send_data)); data->xfer = X; data->conn = conn; - data->document = D; - data->encr_document = ED; + data->msg = msg; X->data = data; } } @@ -228,7 +252,7 @@ PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who) { if (X) { purple_xfer_set_init_fnc (X, tgprpl_xfer_send_init); purple_xfer_set_cancel_send_fnc (X, tgprpl_xfer_canceled); - tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL, NULL); + tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL); } return (PurpleXfer *)X; @@ -244,33 +268,34 @@ static PurpleXfer *tgprpl_new_xfer_recv (PurpleConnection * gc, const char *who) return X; } -void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_document *D) { +void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_message *M) { debug ("tgprpl_recv_file()"); PurpleXfer *X = tgprpl_new_xfer_recv (gc, who); - - char *filename = tgp_strdup_determine_filename (D->mime_type, D->caption, D->flags, - D->access_hash); - purple_xfer_set_filename (X, filename); - g_free (filename); - - purple_xfer_set_size (X, D->size); + const char *mime_type, *caption; + long long access_hash; + int flags, size; - tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), D, NULL); - purple_xfer_request (X); -} + if (M->media.type == tgl_message_media_document_encr) { + mime_type = M->media.encr_document->mime_type; + caption = M->media.encr_document->caption; + access_hash = M->media.encr_document->access_hash; + flags = M->media.encr_document->flags; + size = M->media.encr_document->size; + } else { + mime_type = M->media.document->mime_type; + caption = M->media.document->caption; + access_hash = M->media.document->access_hash; + flags = M->media.document->flags; + size = M->media.document->size; + } -void tgprpl_recv_encr_file (PurpleConnection * gc, const char *who, struct tgl_encr_document *D) { - debug ("tgprpl_recv_encr_file()"); - PurpleXfer *X = tgprpl_new_xfer_recv (gc, who); - - char *filename = tgp_strdup_determine_filename (D->mime_type, D->caption, D->flags, - D->access_hash); + char *filename = tgp_strdup_determine_filename (mime_type, caption, flags, access_hash); purple_xfer_set_filename (X, filename); g_free (filename); - purple_xfer_set_size (X, D->size); + purple_xfer_set_size (X, size); - tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), NULL, D); + tgprpl_xfer_init_data (X, purple_connection_get_protocol_data (gc), M); purple_xfer_request (X); } diff --git a/tgp-ft.h b/tgp-ft.h index ba32bccf..2db5aa7f 100644 --- a/tgp-ft.h +++ b/tgp-ft.h @@ -28,8 +28,8 @@ PurpleXfer *tgprpl_new_xfer (PurpleConnection * gc, const char *who); void tgprpl_send_file (PurpleConnection * gc, const char *who, const char *file); -void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_document *D); -void tgprpl_recv_encr_file (PurpleConnection * gc, const char *who, struct tgl_encr_document *D); +void tgprpl_recv_file (PurpleConnection * gc, const char *who, struct tgl_message *M); +void tgprpl_recv_encr_file (PurpleConnection * gc, const char *who, struct tgl_message *M); void tgprpl_xfer_free_all (connection_data *conn); #endif diff --git a/tgp-msg.c b/tgp-msg.c index ea3beb2d..36917883 100644 --- a/tgp-msg.c +++ b/tgp-msg.c @@ -26,8 +26,10 @@ #include #include #include +#include #include "telegram-purple.h" +#include "telegram-base.h" #include "tgp-structs.h" #include "tgp-msg.h" #include "tgp-ft.h" @@ -123,33 +125,30 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { return txt; } -static char *format_message (struct tgl_message *M) { - switch (M->media.type) { - case tgl_message_media_contact: - return g_strdup_printf ("%s %s
%s", M->media.first_name, M->media.last_name, M->media.phone); - break; - case tgl_message_media_geo: - return g_strdup_printf ("" - "http://openstreetmap.org/?lat=%f&lon=%f&zoom=20", - M->media.geo.latitude, M->media.geo.longitude, - M->media.geo.latitude, M->media.geo.longitude); - return g_strdup_printf ("%s %s
%s", M->media.first_name, M->media.last_name, M->media.phone); - break; - default: - if (*M->message != 0) { - return purple_markup_escape_text (M->message, strlen (M->message)); - } - return NULL; - break; - } +static char *format_geo_link_osm (double lat, double lon) { + + // assure that the floats are formatted with a dot + char *loc = setlocale (LC_NUMERIC, NULL); + setlocale (LC_NUMERIC, "en_US"); + debug ("old locale: %s", loc); + + char *link = g_strdup_printf ("https://www.openstreetmap.org/?mlat=%.6lf&mlon=%.6lf#map=17/%.6lf/%.6lf", + lat, lon, lat, lon); + + // restore old locale + setlocale (LC_NUMERIC, loc); + return link; } static void tgp_msg_send_done (struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M) { if (! success) { - const char *err = "Sending message failed. Maybe you don't have the permission " - "to send to this peer, or the peer does no longer exist."; + char *err = g_strdup_printf("Sending message failed. %d: %s", TLS->error_code, TLS->error); warning (err); tgp_msg_err_out (TLS, err, M->to_id); + g_free (err); + } else if (tgl_get_peer_type(M->to_id) == TGL_PEER_ENCR_CHAT) { + debug ("SUCCESS write_secret_chat_file ..."); + write_secret_chat_file (TLS); } } @@ -162,7 +161,7 @@ static gboolean tgp_msg_send_schedule_cb (gpointer data) { g_queue_pop_head (conn->out_messages); // TODO: option for disable_msg_preview - tgl_do_send_message(D->TLS, D->to, D->msg, (int)strlen (D->msg), 0, tgp_msg_send_done, NULL); + tgl_do_send_message (D->TLS, D->to, D->msg, (int)strlen (D->msg), 0, NULL, tgp_msg_send_done, NULL); tgp_msg_sending_free (D); } return FALSE; @@ -213,42 +212,55 @@ static void tgp_msg_err_out (struct tgl_state *TLS, const char *error, tgl_peer_ } } +void send_inline_picture_done (struct tgl_state *TLS, void *extra, int success, struct tgl_message *msg) { + if (!success) { + char *errormsg = g_strdup_printf ("%d: %s", TLS->error_code, TLS->error); + failure (errormsg); + purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, "Sending image failed.", + errormsg, NULL, NULL, NULL); + return; + } +} + int tgp_msg_send (struct tgl_state *TLS, const char *message, tgl_peer_id_t to) { // search for outgoing embedded image tags and send them gchar *img = NULL; gchar *stripped = NULL; + if ((img = g_strrstr (message, " 0) { PurpleStoredImage *psi = purple_imgstore_find_by_id (imgid); - gchar *tmp = g_build_filename(g_get_tmp_dir(), purple_imgstore_get_filename (psi), NULL) ; + gchar *tmp = g_build_filename (g_get_tmp_dir(), purple_imgstore_get_filename (psi), NULL) ; GError *err = NULL; gconstpointer data = purple_imgstore_get_data (psi); g_file_set_contents (tmp, data, purple_imgstore_get_size (psi), &err); if (! err) { - stripped = purple_markup_strip_html (message); - tgl_do_send_document (TLS, to, tmp, stripped, (int)strlen (stripped), TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgp_msg_send_done, NULL); + stripped = g_strstrip(purple_markup_strip_html (message)); + tgl_do_send_document (TLS, to, tmp, stripped, (int)strlen (stripped), + TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, send_inline_picture_done, NULL); g_free (stripped); - return 1; + + // return 0 to assure that the picture is not echoed, since + // it will already be echoed with the outgoing message + return 0; } else { - failure ("Cannot store image, temp directory not available: %s\n", err->message); + failure ("Storing %s in imagestore failed: %s\n", tmp, err->message); g_error_free (err); - return 0; + return -1; } } } // no image id found in image - return 0; + return -1; } #ifndef __ADIUM_ @@ -277,79 +289,177 @@ int tgp_msg_send (struct tgl_state *TLS, const char *message, tgl_peer_id_t to) return tgp_msg_send_split (TLS, message, to); } +static char *tgp_msg_photo_display (struct tgl_state *TLS, const char *filename, int *flags) { + connection_data *conn = TLS->ev_base; + int img = p2tgl_imgstore_add_with_id (filename); + if (img <= 0) { + failure ("Cannot display picture, adding to imgstore failed."); + return NULL; + } + used_images_add (conn, img); + *flags |= PURPLE_MESSAGE_IMAGES; + return tgp_format_img (img); +} + +static char *tgp_msg_sticker_display (struct tgl_state *TLS, const char *filename, int *flags) { + connection_data *conn = TLS->ev_base; + char *text = NULL; + +#ifdef HAVE_LIBWEBP + int img = p2tgl_imgstore_add_with_id_webp ((char *) filename); + if (img <= 0) { + failure ("Cannot display sticker, adding to imgstore failed"); + return NULL; + } + used_images_add (conn, img); + text = tgp_format_img (img); + *flags |= PURPLE_MESSAGE_IMAGES; +#else + char *txt_user = p2tgl_strdup_alias (tgl_peer_get (TLS, M->from_id)); + text = g_strdup_printf ("%s sent a sticker", txt_user); + *flags |= PURPLE_MESSAGE_SYSTEM; + g_free (txt_user); +#endif + return text; +} + static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) { connection_data *conn = TLS->ev_base; struct tgl_message *M = C->msg; char *text = NULL; int flags = 0; + + if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) { + return; + } + if (!(M->flags & TGLMF_CREATED)) { + return; + } + if (!tgl_get_peer_type (M->to_id)) { + warning ("Bad msg\n"); + return; + } // only display new messages, ignore updates or deletions - if ((M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) || - !(M->flags & TGLMF_CREATED) || - !M->message || - tgp_outgoing_msg (TLS, M) || - !tgl_get_peer_type (M->to_id)) { + if (!M->message || tgp_outgoing_msg (TLS, M) || !tgl_get_peer_type (M->to_id)) { return; } + // format the message text if (M->flags & TGLMF_SERVICE) { text = format_service_msg (TLS, M); flags |= PURPLE_MESSAGE_SYSTEM; - } - else if (M->media.type == tgl_message_media_document && M->media.document->flags & TGLDF_STICKER) { -#ifdef HAVE_LIBWEBP - char *filename = C->data; - int img = p2tgl_imgstore_add_with_id_webp (filename); - if (img <= 0) { failure ("Cannot display sticker, adding to imgstore failed"); return; } - used_images_add (conn, img); - text = format_img_full (img); - flags |= PURPLE_MESSAGE_IMAGES; - g_free (filename); -#else - char *txt_user = p2tgl_strdup_alias (tgl_peer_get (TLS, M->from_id)); - text = g_strdup_printf ("%s sent a sticker", txt_user); - flags |= PURPLE_MESSAGE_SYSTEM; - g_free (txt_user); -#endif - } - else if (M->media.type == tgl_message_media_photo || - (M->media.type == tgl_message_media_document_encr && M->media.encr_document->flags & TGLDF_IMAGE)) { - char *filename = C->data; - int img = p2tgl_imgstore_add_with_id (filename); - if (img <= 0) { - failure ("Cannot display picture message, adding to imgstore failed."); - return; - } - used_images_add (conn, img); - text = format_img_full (img); - flags |= PURPLE_MESSAGE_IMAGES; - g_free (filename); - } - else if (M->media.type == tgl_message_media_document) { - char *who = p2tgl_strdup_id (M->from_id); - if (! tgp_our_msg(TLS, M)) { - tgprpl_recv_file (conn->gc, who, M->media.document); + + } else if (M->media.type != tgl_message_media_none) { + switch (M->media.type) { + + case tgl_message_media_photo: { + assert (C->data); + text = tgp_msg_photo_display (TLS, C->data, &flags); + if (str_not_empty (text)) { + if (str_not_empty (M->media.caption)) { + char *old = text; + text = g_strdup_printf ("%s
%s", old, M->media.caption); + g_free (old); + } + } + break; + } + + case tgl_message_media_document: + if (M->media.document->flags & TGLDF_STICKER) { + assert (C->data); + text = tgp_msg_sticker_display (TLS, C->data, &flags); + } else if (M->media.document->flags & TGLDF_IMAGE) { + assert (C->data); + text = tgp_msg_photo_display (TLS, C->data, &flags); + } else { + char *who = p2tgl_strdup_id (M->from_id); + if (! tgp_our_msg(TLS, M)) { + tgprpl_recv_file (conn->gc, who, M); + } + return; + } + break; + + case tgl_message_media_video: + case tgl_message_media_audio: { + char *who = p2tgl_strdup_id (M->from_id); + if (! tgp_our_msg(TLS, M)) { + tgprpl_recv_file (conn->gc, who, M); + } + } + break; + + case tgl_message_media_document_encr: + if (M->media.encr_document->flags & TGLDF_STICKER) { + assert (C->data); + text = tgp_msg_sticker_display (TLS, C->data, &flags); + } if (M->media.encr_document->flags & TGLDF_IMAGE) { + assert (C->data); + text = tgp_msg_photo_display (TLS, C->data, &flags); + } else { + char *who = p2tgl_strdup_id (M->to_id); + if (! tgp_our_msg(TLS, M)) { + tgprpl_recv_file (conn->gc, who, M); + } + return; + } + break; + + case tgl_message_media_contact: + text = g_strdup_printf ("%s %s %s", M->media.first_name, M->media.last_name, M->media.phone); + break; + + case tgl_message_media_venue: { + char *address = NULL; + if (M->media.venue.address && strcmp (M->media.venue.title, M->media.venue.address)) { + address = g_strdup_printf (" %s", M->media.venue.address); + } + text = g_strdup_printf ("%s%s", + format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude), + M->media.venue.title ? M->media.venue.title : "", address ? address : ""); + if (address) { + g_free (address); + } + break; + } + + case tgl_message_media_geo: + text = g_strdup_printf ("%s", + format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude), + format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude)); + break; + + case tgl_message_media_webpage: { + char *msg = g_strdup (M->message); + text = purple_markup_escape_text (msg, strlen (msg)); + g_free (msg); + break; + } + + default: + warning ("received unknown media type: %d", M->media.type); + break; } - g_free (who); - return; - } - else if (M->media.type == tgl_message_media_document_encr) { - char *who = p2tgl_strdup_id (M->to_id); - if (! tgp_our_msg(TLS, M)) { - tgprpl_recv_encr_file (conn->gc, who, M->media.encr_document); + + } else { + if (str_not_empty (M->message)) { + text = purple_markup_escape_text (M->message, strlen (M->message)); } - g_free (who); - return; - } - else { - text = format_message (M); flags |= PURPLE_MESSAGE_RECV; } - if (! text || ! *text) { + if (! (M->flags & TGLMF_UNREAD)) { + flags |= PURPLE_MESSAGE_DELAYED; + } + + if (! str_not_empty (text)) { warning ("No text to display"); return; } + + // display the message to the user switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHAT: { if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) { @@ -400,11 +510,16 @@ static void tgp_msg_process_in_ready (struct tgl_state *TLS) { } g_queue_pop_head (conn->new_messages); tgp_msg_display (TLS, C); + if (C->data) { + // must al + g_free (C->data); + } tgp_msg_loading_free (C); } } static void tgp_msg_on_loaded_document (struct tgl_state *TLS, void *extra, int success, const char *filename) { + assert (success); struct tgp_msg_loading *C = extra; C->data = (void *) g_strdup (filename); C->done = TRUE; @@ -413,32 +528,54 @@ static void tgp_msg_on_loaded_document (struct tgl_state *TLS, void *extra, int void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) { connection_data *conn = TLS->ev_base; - struct tgp_msg_loading *C = tgp_msg_loading_init (TRUE, M); - - if (M->date != 0 && M->date < tgp_msg_oldest_relevant_ts (TLS)) { - debug ("Message from %d on %d too old, ignored.", tgl_get_peer_id (M->from_id), M->date); + if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) { return; } - if (M->media.type == tgl_message_media_photo) { - C->done = FALSE; - tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C); - } - if (M->media.type == tgl_message_media_document_encr && - M->media.encr_document->flags & TGLDF_IMAGE && - !(M->media.encr_document->flags & TGLDF_STICKER)) { - C->done = FALSE; - tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C); + if (!(M->flags & TGLMF_CREATED)) { + return; } - #ifdef HAVE_LIBWEBP - if (M->media.type == tgl_message_media_document && M->media.document->flags & TGLDF_STICKER) { - C->done = FALSE; - tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C); + if (M->date != 0 && M->date < tgp_msg_oldest_relevant_ts (TLS)) { + debug ("Message from %d on %d too old, ignored.", tgl_get_peer_id (M->from_id), M->date); + return; } - #endif - - if (M->media.type == tgl_message_media_geo) { - // TODO: load geo thumbnail + + struct tgp_msg_loading *C = tgp_msg_loading_init (TRUE, M); + if (! (M->flags & TGLMF_SERVICE)) { + // handle all messages that need to load content before they can be displayed + if (M->media.type != tgl_message_media_none) { + switch (M->media.type) { + case tgl_message_media_photo: + C->done = FALSE; + tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C); + break; + + // documents that are stickers or images will be displayed just like regular photo messages + // and need to be lodaed beforehand + case tgl_message_media_document: + case tgl_message_media_video: + case tgl_message_media_audio: + if (M->media.document->flags & TGLDF_STICKER || M->media.document->flags & TGLDF_IMAGE) { + C->done = FALSE; + tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C); + } + break; + case tgl_message_media_document_encr: + if (M->media.encr_document->flags & TGLDF_STICKER || M->media.encr_document->flags & TGLDF_IMAGE) { + C->done = FALSE; + tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C); + } + break; + + case tgl_message_media_geo: + // TODO: load geo thumbnail + break; + + default: + break; + } + } } + g_queue_push_tail (conn->new_messages, C); tgp_msg_process_in_ready (TLS); } diff --git a/tgp-net.c b/tgp-net.c index 24744d01..f9c275f9 100644 --- a/tgp-net.c +++ b/tgp-net.c @@ -66,11 +66,10 @@ static void try_write (struct connection *c); static int ping_alarm (gpointer arg) { struct connection *c = arg; - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG + 2,"ping alarm"); + debug ("ping alarm"); assert (c->state == conn_failed || c->state == conn_ready || c->state == conn_connecting); if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { - vlogprintf (E_WARNING, "fail connection: reason: ping timeout"); + warning ("fail connection: reason: ping timeout"); c->state = conn_failed; fail_connection (c); return FALSE; @@ -119,8 +118,7 @@ static void delete_connection_buffer (struct connection_buffer *b) { } int tgln_write_out (struct connection *c, const void *_data, int len) { - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG, "write_out: %d bytes\n", len); + // debug ( "write_out: %d bytes\n", len); const unsigned char *data = _data; if (!len) { return 0; } assert (len > 0); @@ -232,8 +230,7 @@ static void rotate_port (struct connection *c) { static void conn_try_read (gpointer arg, gint source, PurpleInputCondition cond) { struct connection *c = arg; - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG + 1, "Try read. Fd = %d\n", c->fd); + // debug ("Try read. Fd = %d\n", c->fd); try_read (c); } @@ -253,8 +250,7 @@ static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond static void net_on_connected (gpointer arg, gint fd, const gchar *error_message) { struct connection *c = arg; - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG - 2, "connect result: %d\n", fd); + // debug ("connect result: %d\n", fd); if (c->fail_ev >= 0) { purple_timeout_remove (c->fail_ev); @@ -314,6 +310,7 @@ static void restart_connection (struct connection *c) { struct tgl_state *TLS = c->TLS; connection_data *conn = TLS->ev_base; + /* if (strcmp (c->ip, c->dc->ip) != 0 || c->port != c->dc->port) { info ("DC%d address changed from %s:%d to %s:%d, updating settings.\n", c->dc->id, c->ip, c->port, c->dc->ip, c->dc->port); @@ -323,6 +320,7 @@ static void restart_connection (struct connection *c) { c->ip = strdup (c->dc->ip); c->port = c->dc->port; } + */ if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) { purple_connection_error_reason (conn->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, @@ -369,15 +367,14 @@ static void fail_connection (struct connection *c) { c->prpl_data = NULL; - vlogprintf (E_NOTICE, "Lost connection to server... %s:%d\n", c->ip, c->port); + info ("Lost connection to server... %s:%d\n", c->ip, c->port); purple_connection_error_reason (conn->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, "Lost connection to server..."); } //extern FILE *log_net_f; static void try_write (struct connection *c) { - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG, "try write: fd = %d\n", c->fd); + // debug ("try write: fd = %d\n", c->fd); int x = 0; while (c->out_head) { int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr); @@ -395,7 +392,7 @@ static void try_write (struct connection *c) { delete_connection_buffer (b); } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - vlogprintf (E_NOTICE, "fail_connection: write_error %m\n"); + info ("fail_connection: write_error %m\n"); fail_connection (c); return; } else { @@ -403,7 +400,7 @@ static void try_write (struct connection *c) { } } } - vlogprintf (E_DEBUG, "Sent %d bytes to %d\n", x, c->fd); + // debug ("Sent %d bytes to %d\n", x, c->fd); c->out_bytes -= x; } @@ -446,8 +443,7 @@ static void try_rpc_read (struct connection *c) { } static void try_read (struct connection *c) { - struct tgl_state *TLS = c->TLS; - vlogprintf (E_DEBUG, "try read: fd = %d\n", c->fd); + // debug ( "try read: fd = %d\n", c->fd); if (!c->in_tail) { c->in_head = c->in_tail = new_connection_buffer (1 << 20); } @@ -474,7 +470,7 @@ static void try_read (struct connection *c) { c->in_tail = b; } else { if (errno != EAGAIN && errno != EWOULDBLOCK) { - vlogprintf (E_NOTICE, "fail_connection: read_error %m\n"); + debug ("fail_connection: read_error %m\n"); fail_connection (c); return; } else { @@ -482,7 +478,7 @@ static void try_read (struct connection *c) { } } } - vlogprintf (E_DEBUG, "Received %d bytes from %d\n", x, c->fd); + // debug ("Received %d bytes from %d\n", x, c->fd); c->in_bytes += x; if (x) { try_rpc_read (c); diff --git a/tgp-structs.c b/tgp-structs.c index 214c2852..78396bf7 100644 --- a/tgp-structs.c +++ b/tgp-structs.c @@ -18,6 +18,7 @@ Copyright Matthias Jentsch 2014-2015 */ +#include "telegram-base.h" #include "tgp-structs.h" #include "purple.h" #include "msglog.h" @@ -27,14 +28,10 @@ #include #include -void pending_reads_free_cb (gpointer data) { +static void pending_reads_free_cb (gpointer data) { free (data); } -static void pending_reads_cb (struct tgl_state *TLS, void *extra, int success) { - debug ("ack state: %d", success); -} - static gint pending_reads_compare (gconstpointer a, gconstpointer b) { return !memcmp ((tgl_peer_id_t *)a, (tgl_peer_id_t *)b, sizeof(tgl_peer_id_t)); } @@ -45,7 +42,7 @@ void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS) { tgl_peer_id_t *pending; while ((pending = (tgl_peer_id_t*) g_queue_pop_head(queue))) { - tgl_do_mark_read (TLS, *pending, pending_reads_cb, queue); + tgl_do_mark_read (TLS, *pending, tgp_notify_on_error_gw, NULL); debug ("tgl_do_mark_read (%d)", pending->id); free (pending); } @@ -77,6 +74,7 @@ struct tgp_msg_loading *tgp_msg_loading_init (int done, struct tgl_message *M) { struct tgp_msg_loading *C = malloc (sizeof (struct tgp_msg_loading)); C->done = done; C->msg = M; + C->data = NULL; return C; } diff --git a/tgp-structs.h b/tgp-structs.h index c13eb235..81c35f22 100755 --- a/tgp-structs.h +++ b/tgp-structs.h @@ -53,8 +53,7 @@ struct tgp_xfer_send_data { int done; PurpleXfer *xfer; connection_data *conn; - struct tgl_document *document; - struct tgl_encr_document *encr_document; + struct tgl_message *msg; }; struct download_desc { @@ -79,6 +78,11 @@ struct accept_secret_chat_data { struct tgl_secret_chat *U; }; +struct accept_create_chat_data { + struct tgl_state *TLS; + char *title; +}; + void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS); void pending_reads_add (GQueue *queue, tgl_peer_id_t id); struct message_text *message_text_init (struct tgl_message *M, gchar *text); diff --git a/tgp-utils.c b/tgp-utils.c index 4daa89f3..62a5a515 100644 --- a/tgp-utils.c +++ b/tgp-utils.c @@ -39,7 +39,7 @@ const char *format_time (time_t date) { return purple_utf8_strftime ("%d.%m.%Y %H:%M", datetime); } -char *format_img_full (int imgstore) { +char *tgp_format_img (int imgstore) { const char *br = "
"; //
's look ugly in Adium, but no
will look ugly in Pidgin @@ -142,3 +142,18 @@ const char *tgp_mime_to_filetype (const char *mime) { } return NULL; } + +int tgp_startswith (const char *str, const char *with) { + if (! str || !with) { + return FALSE; + } + int slen = strlen (str), wlen = strlen (with); + if (wlen > slen) { + return FALSE; + } + while (*with) if (*str++ != *with++) { + return FALSE; + } + return TRUE; +} + diff --git a/tgp-utils.h b/tgp-utils.h index c27f0d42..7305c134 100644 --- a/tgp-utils.h +++ b/tgp-utils.h @@ -42,7 +42,7 @@ int tgp_outgoing_msg (struct tgl_state *TLS, struct tgl_message *M); int tgp_our_msg (struct tgl_state *TLS, struct tgl_message *M); const char *format_time (time_t date); -char *format_img_full (int imgstore); +char *tgp_format_img (int imgstore); char *tgp_format_user_status (struct tgl_user_status *status); int str_not_empty (const char *string); long tgp_time_n_days_ago (int days); @@ -50,5 +50,6 @@ char *tgp_g_format_size (gint64 size); void tgp_g_queue_free_full (GQueue *queue, GDestroyNotify free_func); void tgp_g_list_free_full (GList *list, GDestroyNotify free_func); const char *tgp_mime_to_filetype (const char *mime); +int tgp_startswith (const char *str, const char *with); #endif