From 6caf717b59e7e26847a08892b155963dd1601091 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 3 Jul 2014 14:44:42 +0200 Subject: [PATCH 01/36] Incomplete image transfert evolution --- Classes/ChatRoomViewController.h | 2 +- Classes/ChatRoomViewController.m | 45 +++++++++++++++++++++++++-- Classes/ImageSharing.m | 2 +- Classes/LinphoneManager.h | 8 +++++ Classes/LinphoneManager.m | 40 ++++++++++++++++++++++-- Resources/wizard_linphone_create.rc | 2 +- Resources/wizard_linphone_existing.rc | 2 +- 7 files changed, 91 insertions(+), 10 deletions(-) diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index 491accaf4..44f08cc3e 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -29,7 +29,7 @@ #include "linphone/linphonecore.h" -@interface ChatRoomViewController : UIViewController { +@interface ChatRoomViewController : UIViewController { LinphoneChatRoom *chatRoom; ImageSharing *imageSharing; OrderedDictionary *imageQualities; diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index cdfc82e09..a40462b45 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -26,7 +26,12 @@ #import #import "Utils.h" -@implementation ChatRoomViewController +@implementation ChatRoomViewController { + /* Message transfer transient storage */ + /* TODO: use this for data retrieval */ + NSData* image; + size_t offset_sent; +} @synthesize tableController; @synthesize sendButton; @@ -62,6 +67,9 @@ [NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil), [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; self->composingVisible = TRUE; + + self->image = nil; + self->offset_sent = 0; } return self; } @@ -625,8 +633,26 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{ if(imageSharing == nil) { - NSString *urlString = [[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"]; - imageSharing = [ImageSharing newImageSharingUpload:[NSURL URLWithString:urlString] image:image delegate:self userInfo:url]; + NSData* jpegData = UIImageJPEGRepresentation(image, 1.0); + LinphoneContent content = {}; + content.type = "image"; + content.subtype = "jpeg"; + content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); + content.data = (void*)[jpegData bytes]; + content.size = [jpegData length]; + + LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, &content); + linphone_chat_message_set_user_data(message, self); + + if ( url ) { + // internal url is saved in the appdata for display and later save + [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message]; + } + + linphone_chat_room_send_message2(chatRoom, message, message_status, self); + + [tableController addChatEntry:linphone_chat_message_ref(message)]; + [tableController scrollToBottom:true]; [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; return TRUE; @@ -729,6 +755,19 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [self chooseImageQuality:image url:url]; } +#pragma mark - LinphoneChatContentTransferDelegate + +- (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent { + [imageTransferProgressBar setProgress:percent]; +} + +- (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size { + // TODO +} + +- (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size { + // TODO +} #pragma mark - Keyboard Event Functions diff --git a/Classes/ImageSharing.m b/Classes/ImageSharing.m index 6ab27490e..bebc306d0 100644 --- a/Classes/ImageSharing.m +++ b/Classes/ImageSharing.m @@ -92,7 +92,7 @@ - (void)uploadImageTo:(NSURL*)url image:(UIImage*)image { - [LinphoneLogger log:LinphoneLoggerLog format:@"downloading [%@]", [url absoluteString]]; + [LinphoneLogger log:LinphoneLoggerLog format:@"uploading to [%@]", [url absoluteString]]; // setting up the request object now NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 6fa0e1fd7..6546807a3 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -96,6 +96,14 @@ struct NetworkReachabilityContext { }; @end +@protocol LinphoneChatContentTransferDelegate + +-(void)onProgressReport:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content percent:(int)percent; +-(void)onDataRequested:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(char*)buffer withSize:(size_t*)size; +-(void)onDataReceived:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(const char*)buffer withSize:(size_t)size; + +@end + typedef struct _LinphoneManagerSounds { SystemSoundID call; SystemSoundID message; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 3a5927891..9f2a092f0 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -859,7 +859,29 @@ static void linphone_iphone_message_received(LinphoneCore *lc, LinphoneChatRoom [(LinphoneManager*)linphone_core_get_user_data(lc) onMessageReceived:lc room:room message:message]; } -#pragma mark - Message composition start +#pragma mark - FileTransfer functions + +static void linphone_iphone_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) { + id delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Transfer of %s, incoming data (%d bytes)", content->name, size]; + [delegate onDataReceived:message forContent:content buffer:buff withSize:size]; +} + +static void linphone_iphone_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ + id delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Transfer of %s, requesting data (%d bytes)", content->name, *size]; + [delegate onDataRequested:message forContent:content buffer:buff withSize:size]; +} + +static void linphone_iphone_file_transfer_progress(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress){ + id delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Progress of transfer %s: %d%%", content->name, progress]; + [delegate onProgressReport:message forContent:content percent:progress]; +} + + + +#pragma mark - Message composition start - (void)onMessageComposeReceived:(LinphoneCore*)core forRoom:(LinphoneChatRoom*)room { [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextComposeEvent @@ -1022,7 +1044,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach } -#pragma mark - +#pragma mark - VTable static LinphoneCoreVTable linphonec_vtable = { .show =NULL, @@ -1041,9 +1063,15 @@ static LinphoneCoreVTable linphonec_vtable = { .transfer_state_changed=linphone_iphone_transfer_state_changed, .is_composing_received = linphone_iphone_is_composing_received, .configuring_status = linphone_iphone_configuring_status_changed, - .global_state_changed = linphone_iphone_global_state_changed + .global_state_changed = linphone_iphone_global_state_changed, + .file_transfer_received = linphone_iphone_file_transfer_recv, + .file_transfer_send = linphone_iphone_file_transfer_send, + .file_transfer_progress_indication = linphone_iphone_file_transfer_progress + }; +#pragma mark - + //scheduling loop - (void)iterate { linphone_core_iterate(theLinphoneCore); @@ -1111,6 +1139,12 @@ static LinphoneCoreVTable linphonec_vtable = { [self setupNetworkReachabilityCallback]; + NSString *urlString = [self lpConfigStringForKey:@"sharing_server_preference"]; + if( urlString ){ + linphone_core_set_file_transfer_server(theLinphoneCore, [urlString UTF8String]); + } + + NSString* path = [LinphoneManager bundleFile:@"nowebcamCIF.jpg"]; if (path) { const char* imagePath = [path cStringUsingEncoding:[NSString defaultCStringEncoding]]; diff --git a/Resources/wizard_linphone_create.rc b/Resources/wizard_linphone_create.rc index 53c05f61c..0780368e9 100644 --- a/Resources/wizard_linphone_create.rc +++ b/Resources/wizard_linphone_create.rc @@ -18,7 +18,7 @@
1 - https://www.linphone.org:444/upload.php + https://www.linphone.org:444/lft.php 1 stun.linphone.org 1 diff --git a/Resources/wizard_linphone_existing.rc b/Resources/wizard_linphone_existing.rc index 74b948d8a..6bbcf1a49 100644 --- a/Resources/wizard_linphone_existing.rc +++ b/Resources/wizard_linphone_existing.rc @@ -18,7 +18,7 @@
1 - https://www.linphone.org:444/upload.php + https://www.linphone.org:444/lft.php 1 stun.linphone.org 1 From e6045a2c60f90851a98c544373d02ce3b6e8954d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:31:50 +0200 Subject: [PATCH 02/36] Removed / corrected code spotted by static analysis --- Classes/ChatRoomTableViewController.m | 1 + Classes/ChatRoomViewController.m | 2 +- Classes/HistoryDetailsViewController.m | 12 ------------ Classes/LinphoneManager.m | 1 + Classes/LinphoneUI/UIChatRoomCell.m | 2 ++ .../Controllers/IASKSpecifierValuesViewController.m | 1 + 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 323c6943a..6533dbfc1 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -47,6 +47,7 @@ // chatRoom = NULL; } - (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; [self reloadData]; } diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index a40462b45..026e1fc87 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -240,10 +240,10 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - } -(void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; [TUNinePatchCache flushCache]; // will remove any images cache (freeing any cached but unused images) } diff --git a/Classes/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index dfaf43580..108848ba9 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -385,18 +385,6 @@ static UICompositeViewDescription *compositeDescription = nil; if(lAddress == NULL) return; - NSString *displayName = nil; - if(contact != nil) { - displayName = [FastAddressBook getContactDisplayName:contact]; - } else { - const char* lDisplayName = linphone_address_get_display_name(addr); - const char* lUserName = linphone_address_get_username(addr); - if (lDisplayName) - displayName = [NSString stringWithUTF8String:lDisplayName]; - else if(lUserName) - displayName = [NSString stringWithUTF8String:lUserName]; - } - // Go to ChatRoom view [[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]]; ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 34dc82399..24eeab399 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1890,6 +1890,7 @@ static void audioRouteChangeListenerCallback ( NSData* data = [NSJSONSerialization dataWithJSONObject:appDataDict options:0 error:nil]; NSString* appdataJSON = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; linphone_chat_message_set_appdata(msg, [appdataJSON UTF8String] ); + [appdataJSON release]; } #pragma mark - LPConfig Functions diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index eea11e183..19561be8b 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -140,6 +140,8 @@ static UIFont *CELL_FONT = nil; [messageImageView stopLoading]; [image release]; }); + } else { + [image release]; } }); } failureBlock:^(NSError *error) { diff --git a/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m b/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m index bd0b82ac6..d5d9449b4 100755 --- a/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m +++ b/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m @@ -105,6 +105,7 @@ } - (void)viewDidUnload { + [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.tableView = nil; From 33d645dfc5c10259644d40810e46b5112af5d4be Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:43:43 +0200 Subject: [PATCH 03/36] Update linphone and belle-sip --- submodules/belle-sip | 2 +- submodules/linphone | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/belle-sip b/submodules/belle-sip index 46c40fd48..e25ef8504 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 46c40fd4809dd8d46a6568fa1245150711ec27fd +Subproject commit e25ef850442577adbab07be82112b279ceded9e3 diff --git a/submodules/linphone b/submodules/linphone index 7f4afe295..214521c5a 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 7f4afe2954c1f92df5ca57e2a14e44e152e2b244 +Subproject commit 214521c5a87048b81bb7f6ae278782db5ab4e124 From 974fe07e2b479301942d8dc75148548980ed9e0c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:45:16 +0200 Subject: [PATCH 04/36] Update msopenh264 --- submodules/msopenh264 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/msopenh264 b/submodules/msopenh264 index ae2270dca..bba709ebd 160000 --- a/submodules/msopenh264 +++ b/submodules/msopenh264 @@ -1 +1 @@ -Subproject commit ae2270dcaaabb0cc5980783fc5fb6ac5365ee03f +Subproject commit bba709ebd9fccf0ec2e895275a5bea3c27eece13 From 77dfa1c6b3af146a81445d9e69b82e675f52c955 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:11:46 +0200 Subject: [PATCH 05/36] Added block-based UIAlertview handler. This will ease development --- .../UIAlertView+Blocks/UIAlertView+Blocks.h | 59 ++++ .../UIAlertView+Blocks/UIAlertView+Blocks.m | 264 ++++++++++++++++++ Resources/licenses.html | 23 +- linphone.xcodeproj/project.pbxproj | 17 ++ 4 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h create mode 100644 Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m diff --git a/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h new file mode 100644 index 000000000..d5372d8d2 --- /dev/null +++ b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h @@ -0,0 +1,59 @@ +// +// UIAlertView+Blocks.h +// UIAlertViewBlocks +// +// Created by Ryan Maxwell on 29/08/13. +// +// The MIT License (MIT) +// +// Copyright (c) 2013 Ryan Maxwell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#import + +typedef void (^UIAlertViewBlock) (UIAlertView *alertView); +typedef void (^UIAlertViewCompletionBlock) (UIAlertView *alertView, NSInteger buttonIndex); + +@interface UIAlertView (Blocks) + ++ (instancetype)showWithTitle:(NSString *)title + message:(NSString *)message + style:(UIAlertViewStyle)style + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + tapBlock:(UIAlertViewCompletionBlock)tapBlock; + ++ (instancetype)showWithTitle:(NSString *)title + message:(NSString *)message + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + tapBlock:(UIAlertViewCompletionBlock)tapBlock; + +@property (copy, nonatomic) UIAlertViewCompletionBlock tapBlock; +@property (copy, nonatomic) UIAlertViewCompletionBlock willDismissBlock; +@property (copy, nonatomic) UIAlertViewCompletionBlock didDismissBlock; + +@property (copy, nonatomic) UIAlertViewBlock willPresentBlock; +@property (copy, nonatomic) UIAlertViewBlock didPresentBlock; +@property (copy, nonatomic) UIAlertViewBlock cancelBlock; + +@property (copy, nonatomic) BOOL(^shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView); + +@end diff --git a/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m new file mode 100644 index 000000000..2cdfd71ff --- /dev/null +++ b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m @@ -0,0 +1,264 @@ +// +// UIAlertView+Blocks.m +// UIAlertViewBlocks +// +// Created by Ryan Maxwell on 29/08/13. +// +// The MIT License (MIT) +// +// Copyright (c) 2013 Ryan Maxwell +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#import "UIAlertView+Blocks.h" + +#import + +static const void *UIAlertViewOriginalDelegateKey = &UIAlertViewOriginalDelegateKey; + +static const void *UIAlertViewTapBlockKey = &UIAlertViewTapBlockKey; +static const void *UIAlertViewWillPresentBlockKey = &UIAlertViewWillPresentBlockKey; +static const void *UIAlertViewDidPresentBlockKey = &UIAlertViewDidPresentBlockKey; +static const void *UIAlertViewWillDismissBlockKey = &UIAlertViewWillDismissBlockKey; +static const void *UIAlertViewDidDismissBlockKey = &UIAlertViewDidDismissBlockKey; +static const void *UIAlertViewCancelBlockKey = &UIAlertViewCancelBlockKey; +static const void *UIAlertViewShouldEnableFirstOtherButtonBlockKey = &UIAlertViewShouldEnableFirstOtherButtonBlockKey; + +@implementation UIAlertView (Blocks) + ++ (instancetype)showWithTitle:(NSString *)title + message:(NSString *)message + style:(UIAlertViewStyle)style + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + tapBlock:(UIAlertViewCompletionBlock)tapBlock { + + NSString *firstObject = otherButtonTitles.count ? otherButtonTitles[0] : nil; + + UIAlertView *alertView = [[self alloc] initWithTitle:title + message:message + delegate:nil + cancelButtonTitle:cancelButtonTitle + otherButtonTitles:firstObject, nil]; + + alertView.alertViewStyle = style; + + if (otherButtonTitles.count > 1) { + for (NSString *buttonTitle in [otherButtonTitles subarrayWithRange:NSMakeRange(1, otherButtonTitles.count - 1)]) { + [alertView addButtonWithTitle:buttonTitle]; + } + } + + if (tapBlock) { + alertView.tapBlock = tapBlock; + } + + [alertView show]; + +#if !__has_feature(objc_arc) + return [alertView autorelease]; +#else + return alertView; +#endif +} + + ++ (instancetype)showWithTitle:(NSString *)title + message:(NSString *)message + cancelButtonTitle:(NSString *)cancelButtonTitle + otherButtonTitles:(NSArray *)otherButtonTitles + tapBlock:(UIAlertViewCompletionBlock)tapBlock { + + return [self showWithTitle:title + message:message + style:UIAlertViewStyleDefault + cancelButtonTitle:cancelButtonTitle + otherButtonTitles:otherButtonTitles + tapBlock:tapBlock]; +} + +#pragma mark - + +- (void)_checkAlertViewDelegate { + if (self.delegate != (id)self) { + objc_setAssociatedObject(self, UIAlertViewOriginalDelegateKey, self.delegate, OBJC_ASSOCIATION_ASSIGN); + self.delegate = (id)self; + } +} + +- (UIAlertViewCompletionBlock)tapBlock { + return objc_getAssociatedObject(self, UIAlertViewTapBlockKey); +} + +- (void)setTapBlock:(UIAlertViewCompletionBlock)tapBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewTapBlockKey, tapBlock, OBJC_ASSOCIATION_COPY); +} + +- (UIAlertViewCompletionBlock)willDismissBlock { + return objc_getAssociatedObject(self, UIAlertViewWillDismissBlockKey); +} + +- (void)setWillDismissBlock:(UIAlertViewCompletionBlock)willDismissBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewWillDismissBlockKey, willDismissBlock, OBJC_ASSOCIATION_COPY); +} + +- (UIAlertViewCompletionBlock)didDismissBlock { + return objc_getAssociatedObject(self, UIAlertViewDidDismissBlockKey); +} + +- (void)setDidDismissBlock:(UIAlertViewCompletionBlock)didDismissBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewDidDismissBlockKey, didDismissBlock, OBJC_ASSOCIATION_COPY); +} + +- (UIAlertViewBlock)willPresentBlock { + return objc_getAssociatedObject(self, UIAlertViewWillPresentBlockKey); +} + +- (void)setWillPresentBlock:(UIAlertViewBlock)willPresentBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewWillPresentBlockKey, willPresentBlock, OBJC_ASSOCIATION_COPY); +} + +- (UIAlertViewBlock)didPresentBlock { + return objc_getAssociatedObject(self, UIAlertViewDidPresentBlockKey); +} + +- (void)setDidPresentBlock:(UIAlertViewBlock)didPresentBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewDidPresentBlockKey, didPresentBlock, OBJC_ASSOCIATION_COPY); +} + +- (UIAlertViewBlock)cancelBlock { + return objc_getAssociatedObject(self, UIAlertViewCancelBlockKey); +} + +- (void)setCancelBlock:(UIAlertViewBlock)cancelBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY); +} + +- (void)setShouldEnableFirstOtherButtonBlock:(BOOL(^)(UIAlertView *alertView))shouldEnableFirstOtherButtonBlock { + [self _checkAlertViewDelegate]; + objc_setAssociatedObject(self, UIAlertViewShouldEnableFirstOtherButtonBlockKey, shouldEnableFirstOtherButtonBlock, OBJC_ASSOCIATION_COPY); +} + +- (BOOL(^)(UIAlertView *alertView))shouldEnableFirstOtherButtonBlock { + return objc_getAssociatedObject(self, UIAlertViewShouldEnableFirstOtherButtonBlockKey); +} + +#pragma mark - UIAlertViewDelegate + +- (void)willPresentAlertView:(UIAlertView *)alertView { + UIAlertViewBlock block = alertView.willPresentBlock; + + if (block) { + block(alertView); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(willPresentAlertView:)]) { + [originalDelegate willPresentAlertView:alertView]; + } +} + +- (void)didPresentAlertView:(UIAlertView *)alertView { + UIAlertViewBlock block = alertView.didPresentBlock; + + if (block) { + block(alertView); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(didPresentAlertView:)]) { + [originalDelegate didPresentAlertView:alertView]; + } +} + + +- (void)alertViewCancel:(UIAlertView *)alertView { + UIAlertViewBlock block = alertView.cancelBlock; + + if (block) { + block(alertView); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertViewCancel:)]) { + [originalDelegate alertViewCancel:alertView]; + } +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + UIAlertViewCompletionBlock completion = alertView.tapBlock; + + if (completion) { + completion(alertView, buttonIndex); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)]) { + [originalDelegate alertView:alertView clickedButtonAtIndex:buttonIndex]; + } +} + +- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { + UIAlertViewCompletionBlock completion = alertView.willDismissBlock; + + if (completion) { + completion(alertView, buttonIndex); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)]) { + [originalDelegate alertView:alertView willDismissWithButtonIndex:buttonIndex]; + } +} + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + UIAlertViewCompletionBlock completion = alertView.didDismissBlock; + + if (completion) { + completion(alertView, buttonIndex); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)]) { + [originalDelegate alertView:alertView didDismissWithButtonIndex:buttonIndex]; + } +} + +- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView { + BOOL(^shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView) = alertView.shouldEnableFirstOtherButtonBlock; + + if (shouldEnableFirstOtherButtonBlock) { + return shouldEnableFirstOtherButtonBlock(alertView); + } + + id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey); + if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)]) { + return [originalDelegate alertViewShouldEnableFirstOtherButton:alertView]; + } + + return YES; +} + +@end diff --git a/Resources/licenses.html b/Resources/licenses.html index a30fe2bed..38e6bca0e 100644 --- a/Resources/licenses.html +++ b/Resources/licenses.html @@ -2,56 +2,73 @@

Third party softwares

+

CAAnimationBlocks

Xissburg
http://xissburg.com

+

ColorConverter

Matteo Alessani
http://www.extendi.it

+

DCRoundSwitch

Patrick Richards
http://domesticcat.com.au
MIT license

+

DTFoundation

Oliver Drobnik
http://www.cocoanetics.com
BSD license

+

HPGrowingTextView

Hans Pinckaers
http://hanspinckaers.com
MIT license

+

InAppSettingsKit

Luc Vandal, Edovia Inc., Ortwin Gentz, FutureTap GmbH
http://www.inappsettingskit.com/
BSD license

+

NinePatch

Tortuga 22, Inc.
http://www.tortuga22.com
Apache license

+ +

Ryan Maxwell

+

UIAlertview+Blocks

+https://github.com/ryanmaxwell/UIAlertView-Blocks
+MIT license +

OrderedDictionary

Matt Gallagher
http://cocoawithlove.com

+

TPMultiLayoutViewController

Michael Tyson
http://atastypixel.com
MIT license

+

UACellBackgroundView

Matt Coneybeare
http://code.coneybeare.net

+

XMLRPC

Eric Czarny
http://divisiblebyzero.com/
MIT license

+

Graphics

+

Kerosine

http://www.kerosine.fr

+

Translations

+

Russian

Maxim Solodovnik
solomax666@gmail.com

-

Utilitary softwares

-

Localization Suite

-

http://www.loc-suite.org

diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 9a045321d..edd8efc3a 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -1428,6 +1428,8 @@ F0BB8C48193630CA00974404 /* userdb.conf in Resources */ = {isa = PBXBuildFile; fileRef = F0BB8C43193630CA00974404 /* userdb.conf */; }; F0BB8C4C193631D200974404 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22276E8813C73DC000210156 /* CoreMedia.framework */; }; F0BB8C4D193631DF00974404 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 224567C1107B968500F10948 /* AVFoundation.framework */; }; + F0D00DE2196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */; }; + F0D00DE3196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */; }; F476004B147AAF2800FFF19B /* liblinphone.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2211DB911475562600DEE054 /* liblinphone.a */; }; F84015BF1939FE37006ABAB5 /* test_failed.png in Resources */ = {isa = PBXBuildFile; fileRef = F84015BC1939FE37006ABAB5 /* test_failed.png */; }; F84015C01939FE37006ABAB5 /* test_inprogress.png in Resources */ = {isa = PBXBuildFile; fileRef = F84015BD1939FE37006ABAB5 /* test_inprogress.png */; }; @@ -2377,6 +2379,8 @@ F0BB8C42193630CA00974404 /* tester_hosts */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = tester_hosts; path = submodules/linphone/tester/tester_hosts; sourceTree = SOURCE_ROOT; }; F0BB8C43193630CA00974404 /* userdb.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = userdb.conf; path = submodules/linphone/tester/userdb.conf; sourceTree = SOURCE_ROOT; }; F0BB8C4A193631B300974404 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; + F0D00DE0196EB8F40018F6E7 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; + F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; F84015BC1939FE37006ABAB5 /* test_failed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_failed.png; path = Resources/test_failed.png; sourceTree = ""; }; F84015BD1939FE37006ABAB5 /* test_inprogress.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_inprogress.png; path = Resources/test_inprogress.png; sourceTree = ""; }; F84015BE1939FE37006ABAB5 /* test_passed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_passed.png; path = Resources/test_passed.png; sourceTree = ""; }; @@ -2880,6 +2884,7 @@ D3807FB615C28940005BE9BC /* DCRoundSwitch */, D37EE15F160377D7003608A6 /* DTFoundation */, D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */, + F0D00DDF196EB8F40018F6E7 /* UIAlertView+Blocks */, D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */, D3ED40141602172200BF332B /* GrowingTextView */, D3807FC715C2894A005BE9BC /* InAppSettingsKit */, @@ -3598,6 +3603,16 @@ name = "Supporting Files"; sourceTree = ""; }; + F0D00DDF196EB8F40018F6E7 /* UIAlertView+Blocks */ = { + isa = PBXGroup; + children = ( + F0D00DE0196EB8F40018F6E7 /* UIAlertView+Blocks.h */, + F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */, + ); + name = "UIAlertView+Blocks"; + path = "Utils/UIAlertView+Blocks"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -4916,6 +4931,7 @@ D32409C3158B49A600C8C119 /* UILongTouchButton.m in Sources */, D36C43C6158F2E5A0048BA40 /* UICallCell.m in Sources */, D35E7581159328EB0066B1C1 /* UIAddressTextField.m in Sources */, + F0D00DE2196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */, D35E7597159460580066B1C1 /* ChatViewController.m in Sources */, D35E759F159460B70066B1C1 /* SettingsViewController.m in Sources */, F03CA84318C72F1A0008889D /* UITextViewNoDefine.m in Sources */, @@ -5015,6 +5031,7 @@ D32409C4158B49A600C8C119 /* UILongTouchButton.m in Sources */, D36C43C7158F2E5A0048BA40 /* UICallCell.m in Sources */, D35E7582159328EB0066B1C1 /* UIAddressTextField.m in Sources */, + F0D00DE3196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */, D35E7598159460580066B1C1 /* ChatViewController.m in Sources */, D35E75A0159460B70066B1C1 /* SettingsViewController.m in Sources */, F03CA84418C72F1A0008889D /* UITextViewNoDefine.m in Sources */, From 831a7f222f341d5303c6fa7909a1b4769caef269 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:24:15 +0200 Subject: [PATCH 06/36] Add helper functions for Logging --- Classes/Utils/Utils.h | 8 ++++++++ Classes/Utils/Utils.m | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Classes/Utils/Utils.h b/Classes/Utils/Utils.h index 00c7b3eeb..9b2b36a78 100644 --- a/Classes/Utils/Utils.h +++ b/Classes/Utils/Utils.h @@ -62,4 +62,12 @@ typedef enum _LinphoneLoggerSeverity { @end +void Linphone_log(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_dbg(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_warn(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_err(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_fatal(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); + + + #endif diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index b6c97ab26..e68b2187c 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -23,9 +23,8 @@ @implementation LinphoneLogger -+ (void)log:(LinphoneLoggerSeverity) severity format:(NSString *)format,... { - va_list args; - va_start (args, format); + ++ (void)logv:(LinphoneLoggerSeverity)severity format:(NSString*)format args:(va_list)args{ NSString *str = [[NSString alloc] initWithFormat: format arguments:args]; if(severity <= LinphoneLoggerDebug) { ms_debug("%s", [str UTF8String]); @@ -39,6 +38,12 @@ ms_fatal("%s", [str UTF8String]); } [str release]; +} + ++ (void)log:(LinphoneLoggerSeverity) severity format:(NSString *)format,... { + va_list args; + va_start (args, format); + [LinphoneLogger logv:severity format:format args:args]; va_end (args); } @@ -237,3 +242,29 @@ } @end + +#define LOGV(level, argstart) \ + va_list args; \ + va_start(args, argstart); \ + [LinphoneLogger logv:level format:argstart args:args]; \ + va_end(args); + +void Linphone_log(NSString* format, ...){ + LOGV(LinphoneLoggerLog, format); +} + +void Linphone_dbg(NSString* format, ...){ + LOGV(LinphoneLoggerDebug, format); +} + +void Linphone_warn(NSString* format, ...){ + LOGV(LinphoneLoggerWarning, format); +} + +void Linphone_err(NSString* format, ...){ + LOGV(LinphoneLoggerError, format); +} + +void Linphone_fatal(NSString* format, ...){ + LOGV(LinphoneLoggerFatal, format); +} From 7467caa879d375ef723e5e2ab206df3b07740a00 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:27:48 +0200 Subject: [PATCH 07/36] Progress commit on message file transfer: - upload and download works, - download only works for runtime messages. Messages pulled from DB will make belle-sip crash - can't cancel the transfer for the moment (waiting for API to fix that) --- Classes/ChatRoomTableViewController.h | 2 +- Classes/ChatRoomViewController.h | 2 +- Classes/ChatRoomViewController.m | 256 +++++++++++++------------- Classes/LinphoneUI/UIChatRoomCell.m | 4 +- 4 files changed, 136 insertions(+), 128 deletions(-) diff --git a/Classes/ChatRoomTableViewController.h b/Classes/ChatRoomTableViewController.h index 38fc39114..e0b3fcedb 100644 --- a/Classes/ChatRoomTableViewController.h +++ b/Classes/ChatRoomTableViewController.h @@ -23,7 +23,7 @@ @protocol ChatRoomDelegate -- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo; +- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg; - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url; - (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url; diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index 44f08cc3e..aa6492db4 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -29,7 +29,7 @@ #include "linphone/linphonecore.h" -@interface ChatRoomViewController : UIViewController { +@interface ChatRoomViewController : UIViewController { LinphoneChatRoom *chatRoom; ImageSharing *imageSharing; OrderedDictionary *imageQualities; diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 026e1fc87..b9d1a43f6 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -21,6 +21,7 @@ #import "PhoneMainView.h" #import "DTActionSheet.h" #import "UILinphone.h" +#import "UIAlertView+Blocks.h" #import #import @@ -28,9 +29,10 @@ @implementation ChatRoomViewController { /* Message transfer transient storage */ - /* TODO: use this for data retrieval */ - NSData* image; - size_t offset_sent; + NSData* upload_data; + size_t upload_bytes_sent; + + NSMutableData* download_data; } @synthesize tableController; @@ -68,8 +70,9 @@ [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; self->composingVisible = TRUE; - self->image = nil; - self->offset_sent = 0; + self->upload_data = nil; + self->upload_bytes_sent = 0; + self->download_data = nil; } return self; } @@ -199,8 +202,8 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - if(imageSharing) { - [imageSharing cancel]; + if(upload_data || download_data ) { + // TODO: when the API permits it, we should cancel the transfer. } [messageField resignFirstResponder]; @@ -269,7 +272,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)update { if(chatRoom == NULL) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat room header: null contact"]; + Linphone_warn(@"Cannot update chat room header: null contact"); return; } @@ -314,18 +317,17 @@ static UICompositeViewDescription *compositeDescription = nil; static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { ChatRoomViewController* thiz = (ChatRoomViewController*)ud; const char*text = linphone_chat_message_get_text(msg); - [LinphoneLogger log:LinphoneLoggerLog - format:@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)]; + Linphone_log(@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)); [thiz.tableController updateChatEntry:msg]; } - (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL*)externalUrl withInternalURL:(NSURL*)internalUrl { if(![LinphoneManager isLcReady]) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: Linphone core not ready"]; + Linphone_warn(@"Cannot send message: Linphone core not ready"); return FALSE; } if(chatRoom == NULL) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: No chatroom"]; + Linphone_warn(@"Cannot send message: No chatroom"); return FALSE; } @@ -347,35 +349,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (void)saveAndSend:(UIImage*)image url:(NSURL*)url { - if(url == nil) { - [waitView setHidden:FALSE]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [[LinphoneManager instance].photoLibrary - writeImageToSavedPhotosAlbum:image.CGImage - orientation:(ALAssetOrientation)[image imageOrientation] - completionBlock:^(NSURL *assetURL, NSError *error){ - dispatch_async(dispatch_get_main_queue(), ^{ - [waitView setHidden:TRUE]; - if (error) { - [LinphoneLogger log:LinphoneLoggerError format:@"Cannot save image data downloaded [%@]", [error localizedDescription]]; - - UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot write image to photo library", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Ok",nil) - otherButtonTitles:nil ,nil]; - [errorAlert show]; - [errorAlert release]; - return; - } - [LinphoneLogger log:LinphoneLoggerLog format:@"Image saved to [%@]", [assetURL absoluteString]]; - [self chatRoomStartImageUpload:image url:assetURL]; - }); - }]; - }); - } else { - [self chatRoomStartImageUpload:image url:url]; - } + [self chatRoomStartImageUpload:image url:url]; } - (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url { @@ -536,8 +510,19 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark - Action Functions - (IBAction)onBackClick:(id)event { - [self.tableController setChatRoom:NULL]; - [[PhoneMainView instance] popCurrentView]; + if( upload_data != nil || download_data != nil ){ + + [UIAlertView showWithTitle:NSLocalizedString(@"Cancel transfer?", nil) + message:NSLocalizedString(@"You have a transfer in progress, leaving this view will cancel it. Are you sure?", nil) + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) + otherButtonTitles:@[NSLocalizedString(@"Yes", nil)] + tapBlock:^(UIAlertView *alertView, NSInteger buttonIndex) { + if( buttonIndex == 1 ){ + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; + } + }]; + } } - (IBAction)onEditClick:(id)event { @@ -621,9 +606,18 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark ChatRoomDelegate -- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo { - if(imageSharing == nil) { - imageSharing = [ImageSharing newImageSharingDownload:url delegate:self userInfo:userInfo]; +- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg { + if(self->download_data == nil) { + const char* url = linphone_chat_message_get_external_body_url(msg); + Linphone_log(@"Content to download: %s", url); + + if( url == nil ) return FALSE; + + download_data = [[NSMutableData alloc] init]; + + linphone_chat_message_set_user_data(msg, self); + linphone_chat_message_start_file_download(msg); + [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; return TRUE; @@ -632,14 +626,13 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{ - if(imageSharing == nil) { - NSData* jpegData = UIImageJPEGRepresentation(image, 1.0); + if( self->upload_data == nil) { LinphoneContent content = {}; - content.type = "image"; - content.subtype = "jpeg"; - content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); - content.data = (void*)[jpegData bytes]; - content.size = [jpegData length]; + self->upload_data = [UIImageJPEGRepresentation(image, 1.0) retain]; + content.type = "image"; + content.subtype = "jpeg"; + content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); + content.size = [self->upload_data length]; LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, &content); linphone_chat_message_set_user_data(message, self); @@ -649,8 +642,14 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message]; } + // TODO: in the user data, we should maybe put a standalone delegate alloced and retained, instead of self. + // This will make sure that when receiving a memory alert or go to another view, we still send the message linphone_chat_room_send_message2(chatRoom, message, message_status, self); + if( content.name ){ + ms_free(content.name); + } + [tableController addChatEntry:linphone_chat_message_ref(message)]; [tableController scrollToBottom:true]; [messageView setHidden:TRUE]; @@ -666,10 +665,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark ImageSharingDelegate -- (void)imageSharingProgress:(ImageSharing*)aimageSharing progress:(float)progress { - [imageTransferProgressBar setProgress:progress]; -} - - (void)imageSharingAborted:(ImageSharing*)aimageSharing { [messageView setHidden:FALSE]; [transferView setHidden:TRUE]; @@ -677,68 +672,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta imageSharing = nil; } -- (void)imageSharingError:(ImageSharing*)aimageSharing error:(NSError *)error { - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - NSString *url = [aimageSharing.connection.currentRequest.URL absoluteString]; - if (aimageSharing.upload) { - [LinphoneLogger log:LinphoneLoggerError format:@"Cannot upload file to server [%@] because [%@]", url, [error localizedDescription]]; - UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot transfer file to remote contact", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Ok",nil) - otherButtonTitles:nil ,nil]; - [errorAlert show]; - [errorAlert release]; - } else { - [LinphoneLogger log:LinphoneLoggerError format:@"Cannot download file from [%@] because [%@]", url, [error localizedDescription]]; - UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot transfer file from remote contact", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue", nil) - otherButtonTitles:nil, nil]; - [errorAlert show]; - [errorAlert release]; - } - imageSharing = nil; -} - -- (void)imageSharingUploadDone:(ImageSharing*)aimageSharing url:(NSURL*)url{ - [self sendMessage:nil withExterlBodyUrl:url withInternalURL:[aimageSharing userInfo] ]; - - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - imageSharing = nil; -} - -- (void)imageSharingDownloadDone:(ImageSharing*)aimageSharing image:(UIImage *)image { - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - - __block LinphoneChatMessage *chat = (LinphoneChatMessage *)[(NSValue*)[imageSharing userInfo] pointerValue]; - [[LinphoneManager instance].photoLibrary writeImageToSavedPhotosAlbum:image.CGImage - orientation:(ALAssetOrientation)[image imageOrientation] - completionBlock:^(NSURL *assetURL, NSError *error){ - if (error) { - [LinphoneLogger log:LinphoneLoggerError format:@"Cannot save image data downloaded [%@]", [error localizedDescription]]; - - UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot write image to photo library", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Ok",nil) - otherButtonTitles:nil ,nil]; - [errorAlert show]; - [errorAlert release]; - return; - } - [LinphoneLogger log:LinphoneLoggerLog format:@"Image saved to [%@]", [assetURL absoluteString]]; - [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:chat]; - [tableController updateChatEntry:chat]; - }]; - imageSharing = nil; -} - - #pragma mark ImagePickerDelegate - (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info { @@ -758,15 +691,92 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark - LinphoneChatContentTransferDelegate - (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent { - [imageTransferProgressBar setProgress:percent]; + [imageTransferProgressBar setProgress:percent/100.0f]; } - (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size { - // TODO + if( self->upload_data ){ + size_t to_send = *size; + size_t remaining = [upload_data length] - self->upload_bytes_sent; + + Linphone_log(@"Asking %ld bytes, sent %ld of %d, %ld remaining", to_send, self->upload_bytes_sent, [upload_data length], remaining); + + if( remaining < to_send ) to_send = remaining; + + @try { + [upload_data getBytes:(void*)buffer range:NSMakeRange(upload_bytes_sent, to_send)]; + upload_bytes_sent += to_send; + *size = to_send; + } + @catch (NSException *exception) { + Linphone_err(@"Exception: %@", exception); + } + + + if( to_send == 0 || upload_bytes_sent == [upload_data length] ){ + Linphone_log(@"Upload finished, cleanup.."); + [upload_data release]; + upload_data = nil; + upload_bytes_sent = 0; + + // update UI + dispatch_async(dispatch_get_main_queue(), ^{ + [messageView setHidden:FALSE]; + [transferView setHidden:TRUE]; + }); + } + + } else { + Linphone_err(@"Error: no upload data in progress!"); + } } - (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size { - // TODO + if( download_data ){ + Linphone_log(@"Receiving data for %s : %zu bytes, already got %d of %zu",content->name, size, [download_data length], content->size); + + if( size != 0 ){ + [download_data appendBytes:buffer length:size]; + } + + if( size == 0 && [download_data length] == content->size ){ + + Linphone_log(@"Transfer is finished, save image and update chat"); + + dispatch_async(dispatch_get_main_queue(), ^{ + //we're finished, save the image and update the message + [messageView setHidden:FALSE]; + [transferView setHidden:TRUE]; + + UIImage* image = [UIImage imageWithData:download_data]; + + [download_data release]; + download_data = nil; + + [[LinphoneManager instance].photoLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:(ALAssetOrientation)[image imageOrientation] + completionBlock:^(NSURL *assetURL, NSError *error){ + if (error) { + Linphone_err(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + + UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) + message:NSLocalizedString(@"Cannot write image to photo library", nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Ok",nil) + otherButtonTitles:nil ,nil]; + [errorAlert show]; + [errorAlert release]; + return; + } + Linphone_log(@"Image saved to [%@]", [assetURL absoluteString]); + [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:msg]; + [tableController updateChatEntry:msg]; + }]; + + }); + } + } } #pragma mark - Keyboard Event Functions @@ -781,7 +791,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [UIView setAnimationCurve:curve]; [UIView setAnimationBeginsFromCurrentState:TRUE]; CGFloat composeIndicatorCompensation = composingVisible ? composeIndicatorView.frame.size.height : 0.0f; - + // Resize chat view { CGRect chatFrame = [[self chatView] frame]; diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index 19561be8b..18f37676d 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -315,9 +315,7 @@ static UIFont *CELL_FONT = nil; } - (IBAction)onDownloadClick:(id)event { - NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(chat)]]; - [chatRoomDelegate chatRoomStartImageDownload:url userInfo:[NSValue valueWithPointer:chat]]; - + [chatRoomDelegate chatRoomStartImageDownload:chat]; } - (IBAction)onImageClick:(id)event { From d9c51e485456d3b81ce18565d2b2590345268f7e Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:28:02 +0200 Subject: [PATCH 08/36] Use named background task when possible --- Classes/LinphoneManager.m | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 24eeab399..0df79656e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -629,11 +629,19 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char [[UIApplication sharedApplication] presentLocalNotificationNow:data->notification]; if (!incallBgTask){ - incallBgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{ - [LinphoneLogger log:LinphoneLoggerWarning format:@"Call cannot ring any more, too late"]; - [[UIApplication sharedApplication] endBackgroundTask:incallBgTask]; - incallBgTask=0; - }]; + UIApplication* app = [UIApplication sharedApplication]; + + void (^expirationHandler)() = ^{ + [LinphoneLogger log:LinphoneLoggerWarning format:@"Call cannot ring any more, too late"]; + [[UIApplication sharedApplication] endBackgroundTask:incallBgTask]; + incallBgTask=0; + }; + + if( [app respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)] ){ + incallBgTask = [app beginBackgroundTaskWithName:@"Linphone in-call bg task" expirationHandler:expirationHandler]; + } else { + incallBgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler]; + } [[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes]; } From 154f247009c249cfc8a15e1c277586beb7d11f6b Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 17:45:25 +0200 Subject: [PATCH 09/36] Update linphone --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 214521c5a..38ea4ee8a 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 214521c5a87048b81bb7f6ae278782db5ab4e124 +Subproject commit 38ea4ee8a341f58f26406dfb94b7a021980f4872 From d56dc2a972974895f0868ed832ffb825e94a365f Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 11 Jul 2014 09:04:02 +0200 Subject: [PATCH 10/36] Fix back button --- Classes/ChatRoomViewController.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index b9d1a43f6..d09b59024 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -522,6 +522,9 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [[PhoneMainView instance] popCurrentView]; } }]; + } else { + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; } } From 2d702f020e301b8351d0bcd7e7774971d9153c22 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 11 Sep 2014 12:12:10 +0200 Subject: [PATCH 11/36] Update prototypes for new API of linphone chat messages --- Classes/ChatRoomViewController.m | 2 +- Classes/LinphoneManager.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index d09b59024..a787490c6 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -619,7 +619,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta download_data = [[NSMutableData alloc] init]; linphone_chat_message_set_user_data(msg, self); - linphone_chat_message_start_file_download(msg); + linphone_chat_message_start_file_download(msg,NULL); [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index a105fba20..95a0cee4c 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1128,7 +1128,7 @@ static LinphoneCoreVTable linphonec_vtable = { .is_composing_received = linphone_iphone_is_composing_received, .configuring_status = linphone_iphone_configuring_status_changed, .global_state_changed = linphone_iphone_global_state_changed, - .file_transfer_received = linphone_iphone_file_transfer_recv, + .file_transfer_recv = linphone_iphone_file_transfer_recv, .file_transfer_send = linphone_iphone_file_transfer_send, .file_transfer_progress_indication = linphone_iphone_file_transfer_progress From bf216d1806375fabeb7b43bd5fe4b74b6782fa1c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 8 Jun 2015 17:44:04 +0200 Subject: [PATCH 12/36] Ignore OUTPUT/ folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 57e16863b..8b74a154e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ build test-reports WORK Makefile +OUTPUT From 6048e6f8864f3696a406bdafa2250c9bc34aa45a Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 9 Jun 2015 10:26:02 +0200 Subject: [PATCH 13/36] prepare.py: PEP8 reformat and remove x86 from default architectures --- prepare.py | 222 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 124 insertions(+), 98 deletions(-) diff --git a/prepare.py b/prepare.py index 50dd95b81..5df3e9dd6 100755 --- a/prepare.py +++ b/prepare.py @@ -33,71 +33,87 @@ import prepare class IOSTarget(prepare.Target): - def __init__(self, arch): - prepare.Target.__init__(self, 'ios-' + arch) - current_path = os.path.dirname(os.path.realpath(__file__)) - self.config_file = 'configs/config-ios-' + arch + '.cmake' - self.toolchain_file = 'toolchains/toolchain-ios-' + arch + '.cmake' - self.output = 'liblinphone-sdk/' + arch + '-apple-darwin.ios' - self.additional_args = [ - '-DLINPHONE_BUILDER_EXTERNAL_SOURCE_PATH=' + current_path + '/submodules' - ] - def clean(self): - if os.path.isdir('WORK'): - shutil.rmtree('WORK', ignore_errors=False, onerror=self.handle_remove_read_only) - if os.path.isdir('liblinphone-sdk'): - shutil.rmtree('liblinphone-sdk', ignore_errors=False, onerror=self.handle_remove_read_only) + def __init__(self, arch): + prepare.Target.__init__(self, 'ios-' + arch) + current_path = os.path.dirname(os.path.realpath(__file__)) + self.config_file = 'configs/config-ios-' + arch + '.cmake' + self.toolchain_file = 'toolchains/toolchain-ios-' + arch + '.cmake' + self.output = 'liblinphone-sdk/' + arch + '-apple-darwin.ios' + self.additional_args = [ + '-DLINPHONE_BUILDER_EXTERNAL_SOURCE_PATH=' + + current_path + '/submodules' + ] + + def clean(self): + if os.path.isdir('WORK'): + shutil.rmtree( + 'WORK', ignore_errors=False, onerror=self.handle_remove_read_only) + if os.path.isdir('liblinphone-sdk'): + shutil.rmtree( + 'liblinphone-sdk', ignore_errors=False, onerror=self.handle_remove_read_only) class IOSi386Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'i386') + + def __init__(self): + IOSTarget.__init__(self, 'i386') + class IOSx8664Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'x86_64') + + def __init__(self): + IOSTarget.__init__(self, 'x86_64') + class IOSarmv7Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'armv7') + + def __init__(self): + IOSTarget.__init__(self, 'armv7') + class IOSarm64Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'arm64') + + def __init__(self): + IOSTarget.__init__(self, 'arm64') targets = {} -targets[ 'i386'] = IOSi386Target() +targets['i386'] = IOSi386Target() targets['x86_64'] = IOSx8664Target() -targets[ 'armv7'] = IOSarmv7Target() -targets[ 'arm64'] = IOSarm64Target() +targets['armv7'] = IOSarmv7Target() +targets['arm64'] = IOSarm64Target() archs_device = ['arm64', 'armv7'] archs_simu = ['i386', 'x86_64'] platforms = ['all', 'devices', 'simulators'] + archs_device + archs_simu + class PlatformListAction(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - if values: - for value in values: - if value not in platforms: - message = ("invalid platform: {0!r} (choose from {1})".format(value, ', '.join([repr(platform) for platform in platforms]))) - raise argparse.ArgumentError(self, message) - setattr(namespace, self.dest, values) + + def __call__(self, parser, namespace, values, option_string=None): + if values: + for value in values: + if value not in platforms: + message = ("invalid platform: {0!r} (choose from {1})".format( + value, ', '.join([repr(platform) for platform in platforms]))) + raise argparse.ArgumentError(self, message) + setattr(namespace, self.dest, values) + def warning(platforms): - gpl_third_parties_enabled = False - regex = re.compile("^ENABLE_GPL_THIRD_PARTIES:BOOL=ON") - f = open('WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]), 'r') - for line in f: - if regex.match(line): - gpl_third_parties_enabled = True - break - f.close() - - if gpl_third_parties_enabled: - print(""" + gpl_third_parties_enabled = False + regex = re.compile("^ENABLE_GPL_THIRD_PARTIES:BOOL=ON") + f = open( + 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]), 'r') + for line in f: + if regex.match(line): + gpl_third_parties_enabled = True + break + f.close() + + if gpl_third_parties_enabled: + print(""" *************************************************************************** *************************************************************************** ***** CAUTION, this liblinphone SDK is built using 3rd party GPL code ***** @@ -108,8 +124,8 @@ def warning(platforms): *************************************************************************** *************************************************************************** """) - else: - print(""" + else: + print(""" ***************************************************************** ***************************************************************** ***** Linphone SDK without 3rd party GPL software ***** @@ -121,50 +137,60 @@ def warning(platforms): """) -def main(argv = None): - if argv is None: - argv = sys.argv - argparser = argparse.ArgumentParser(description="Prepare build of Linphone and its dependencies.") - argparser.add_argument('-c', '-C', '--clean', help="Clean a previous build instead of preparing a build.", action='store_true') - argparser.add_argument('-d', '--debug', help="Prepare a debug build.", action='store_true') - argparser.add_argument('-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') - argparser.add_argument('-L', '--list-cmake-variables', help="List non-advanced CMake cache variables.", action='store_true', dest='list_cmake_variables') - argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=['all'], help="The platform to build for (default is all), one of: {0}.".format(', '.join([repr(platform) for platform in platforms]))) - args, additional_args = argparser.parse_known_args() +def main(argv=None): + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser( + description="Prepare build of Linphone and its dependencies.") + argparser.add_argument( + '-c', '-C', '--clean', help="Clean a previous build instead of preparing a build.", action='store_true') + argparser.add_argument( + '-d', '--debug', help="Prepare a debug build.", action='store_true') + argparser.add_argument( + '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') + argparser.add_argument('-L', '--list-cmake-variables', + help="List non-advanced CMake cache variables.", action='store_true', + dest='list_cmake_variables') + argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ + 'x86_64', 'devices'], + help="The platform to build for (default is 'x84_64 devices'). Space separated" + " architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) + args, additional_args = argparser.parse_known_args() - selected_platforms = [] - for platform in args.platform: - if platform == 'all': - selected_platforms += archs_device + archs_simu - elif platform == 'devices': - selected_platforms += archs_device - elif platform == 'simulators': - selected_platforms += archs_simu - else: - selected_platforms += [platform] - selected_platforms = list(set(selected_platforms)) + selected_platforms = [] + for platform in args.platform: + if platform == 'all': + selected_platforms += archs_device + archs_simu + elif platform == 'devices': + selected_platforms += archs_device + elif platform == 'simulators': + selected_platforms += archs_simu + else: + selected_platforms += [platform] + selected_platforms = list(set(selected_platforms)) - retcode = 0 - makefile_platforms = [] - for platform in selected_platforms: - target = targets[platform] + retcode = 0 + makefile_platforms = [] + for platform in selected_platforms: + target = targets[platform] - if args.clean: - target.clean() - else: - if args.debug: - additional_args += ["-DENABLE_DEBUG_LOGS=YES"] - retcode = prepare.run(target, args.debug, False, args.list_cmake_variables, args.force, additional_args) - if retcode != 0: - return retcode - makefile_platforms += [platform] + if args.clean: + target.clean() + else: + if args.debug: + additional_args += ["-DENABLE_DEBUG_LOGS=YES"] + retcode = prepare.run( + target, args.debug, False, args.list_cmake_variables, args.force, additional_args) + if retcode != 0: + return retcode + makefile_platforms += [platform] - if makefile_platforms: - packages = os.listdir('WORK/ios-' + makefile_platforms[0] + '/Build') - packages.sort() - arch_targets = "" - for arch in makefile_platforms: - arch_targets += """ + if makefile_platforms: + packages = os.listdir('WORK/ios-' + makefile_platforms[0] + '/Build') + packages.sort() + arch_targets = "" + for arch in makefile_platforms: + arch_targets += """ {arch}: all-{arch} {arch}-build: @@ -223,17 +249,17 @@ def main(argv = None): rm -f WORK/ios-{arch}/Stamp/EP_vpx/*; \\ echo "Run 'make {arch}-build-vpx' to rebuild vpx correctly."; """.format(arch=arch) - multiarch = "" - for arch in makefile_platforms[1:]: - multiarch += \ -""" if test -f "$${arch}_path"; then \\ + multiarch = "" + for arch in makefile_platforms[1:]: + multiarch += \ + """ if test -f "$${arch}_path"; then \\ all_paths=`echo $$all_paths $${arch}_path`; \\ all_archs="$$all_archs,{arch}" ; \\ else \\ echo "WARNING: archive `basename $$archive` exists in {first_arch} tree but does not exists in {arch} tree: $${arch}_path."; \\ fi; \\ """.format(first_arch=makefile_platforms[0], arch=arch) - makefile = """ + makefile = """ archs={archs} packages={packages} LINPHONE_IPHONE_VERSION=$(shell git describe --always) @@ -340,14 +366,14 @@ help: @echo " * sdk : re-add all generated libraries to the SDK. Use this only after a full build." @echo " * libs : after a rebuild of a subpackage, will mix the new libs in liblinphone-sdk/apple-darwin directory" """.format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], arch_targets=arch_targets, packages=' '.join(packages), multiarch=multiarch) - f = open('Makefile', 'w') - f.write(makefile) - f.close() - warning(makefile_platforms) - elif os.path.isfile('Makefile'): - os.remove('Makefile') + f = open('Makefile', 'w') + f.write(makefile) + f.close() + warning(makefile_platforms) + elif os.path.isfile('Makefile'): + os.remove('Makefile') - return retcode + return retcode if __name__ == "__main__": - sys.exit(main()) + sys.exit(main()) From fa4bd8dc7ff4a82a9e1b3f7c27db7990738d408e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 9 Jun 2015 11:46:30 +0200 Subject: [PATCH 14/36] libilbc.mk: rename libilbc.a to libilbcrfc3951.a to be constistent with cmake builder --- submodules/build/builder-iphone-os.mk | 2 +- submodules/build/builders.d/libilbc.mk | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/submodules/build/builder-iphone-os.mk b/submodules/build/builder-iphone-os.mk index 01c8f6cdf..d1273ffa2 100644 --- a/submodules/build/builder-iphone-os.mk +++ b/submodules/build/builder-iphone-os.mk @@ -155,7 +155,7 @@ init: mkdir -p $(prefix)/include mkdir -p $(prefix)/lib/pkgconfig -veryclean: veryclean-linphone +veryclean: veryclean-linphone rm -rf $(BUILDER_BUILD_DIR) list-packages: diff --git a/submodules/build/builders.d/libilbc.mk b/submodules/build/builders.d/libilbc.mk index 6cc5c2411..b52414a0b 100644 --- a/submodules/build/builders.d/libilbc.mk +++ b/submodules/build/builders.d/libilbc.mk @@ -15,7 +15,8 @@ $(LIBILBC_BUILD_DIR)/Makefile: $(LIBILBC_SRC_DIR)/configure $(LIBILBC_SRC_DIR)/configure -prefix=$(prefix) --host=$(host) $(library_mode) build-libilbc: $(LIBILBC_BUILD_DIR)/Makefile - cd $(LIBILBC_BUILD_DIR) && make && make install + cd $(LIBILBC_BUILD_DIR) && make && make install && \ + mv $(prefix)/lib/libilbc.a $(prefix)/lib/libilbcrfc3951.a clean-libilbc: cd $(LIBILBC_BUILD_DIR) && make clean From 9cf91c1452c5a649d479b156be02882a52f84101 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 9 Jun 2015 12:32:53 +0200 Subject: [PATCH 15/36] mssilk: readd in linphone xcode project and update submodule to fix missing generated library --- linphone.xcodeproj/project.pbxproj | 2 ++ submodules/mssilk | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index cc23c79d1..7cf06a6bf 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -125,6 +125,7 @@ 639CEB031A1DF4EB004DE38F /* UICompositeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB051A1DF4EB004DE38F /* UICompositeViewController.xib */; }; 639CEB061A1DF4F1004DE38F /* UIChatRoomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB081A1DF4F1004DE38F /* UIChatRoomCell.xib */; }; 639CEB091A1DF4FA004DE38F /* UIChatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB0B1A1DF4FA004DE38F /* UIChatCell.xib */; }; + 63A4280A1B26F576000DAB93 /* libSKP_SILK_SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 226183AA1472527D0037138E /* libSKP_SILK_SDK.a */; }; 63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CD4B4E1A5AAC8C00B84282 /* DTAlertView.m */; }; 63D2680F1B174A5E00A2CC11 /* numpad_one_voicemail_default.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680D1B174A5E00A2CC11 /* numpad_one_voicemail_default.png */; }; 63D268101B174A5E00A2CC11 /* numpad_one_voicemail_over.png in Resources */ = {isa = PBXBuildFile; fileRef = 63D2680E1B174A5E00A2CC11 /* numpad_one_voicemail_over.png */; }; @@ -1865,6 +1866,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 63A4280A1B26F576000DAB93 /* libSKP_SILK_SDK.a in Frameworks */, 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */, 152F22341B15E83B008C0621 /* libilbcrfc3951.a in Frameworks */, F0B026F31AA710AF00FF49F7 /* libiconv.dylib in Frameworks */, diff --git a/submodules/mssilk b/submodules/mssilk index 06504344a..dd9dd3e81 160000 --- a/submodules/mssilk +++ b/submodules/mssilk @@ -1 +1 @@ -Subproject commit 06504344a367c033598a9dcaa6ff8387269e5a9a +Subproject commit dd9dd3e81719972232d9d4df7bc5e7c5282722bb From fac9e554561bcf74659e60273c9dda93cb43dc90 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 9 Jun 2015 15:37:07 +0200 Subject: [PATCH 16/36] Generate dummy .a libs dynamically according to xcode project. --- prepare.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/prepare.py b/prepare.py index 5df3e9dd6..a46a8f66a 100755 --- a/prepare.py +++ b/prepare.py @@ -137,6 +137,19 @@ def warning(platforms): """) +def extract_libs_list(): + l = [] + regex = re.compile("lib\S+\.a") + f = open('linphone.xcodeproj/project.pbxproj', 'r') + lines = f.readlines() + f.close() + for line in lines: + m = regex.search(line) + if m is not None: + l += [m.group(0)] + return list(set(l)) + + def main(argv=None): if argv is None: argv = sys.argv @@ -186,6 +199,7 @@ def main(argv=None): makefile_platforms += [platform] if makefile_platforms: + libs_list = extract_libs_list() packages = os.listdir('WORK/ios-' + makefile_platforms[0] + '/Build') packages.sort() arch_targets = "" @@ -262,6 +276,7 @@ def main(argv=None): makefile = """ archs={archs} packages={packages} +libs={libs} LINPHONE_IPHONE_VERSION=$(shell git describe --always) .PHONY: all @@ -318,9 +333,11 @@ libs: $(addprefix all-,$(archs)) echo "[$$all_archs] Mixing `basename $$archive` in $$destpath"; \\ lipo -create $$all_paths -output $$destpath; \\ done && \\ - if ! test -f liblinphone-sdk/apple-darwin/lib/libtunnel.a ; then \\ - cp -f submodules/binaries/libdummy.a liblinphone-sdk/apple-darwin/lib/libtunnel.a ; \\ - fi + for lib in $$libs ; do \\ + if ! test -f liblinphone-sdk/apple-darwin/lib/$$lib ; then \\ + cp -f submodules/binaries/libdummy.a liblinphone-sdk/apple-darwin/lib/$$lib ; \\ + fi \\ + done ipa: build xcodebuild -configuration Release \\ @@ -365,7 +382,7 @@ help: @echo "" @echo " * sdk : re-add all generated libraries to the SDK. Use this only after a full build." @echo " * libs : after a rebuild of a subpackage, will mix the new libs in liblinphone-sdk/apple-darwin directory" -""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], arch_targets=arch_targets, packages=' '.join(packages), multiarch=multiarch) +""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], arch_targets=arch_targets, packages=' '.join(packages), libs=' '.join(libs_list), multiarch=multiarch) f = open('Makefile', 'w') f.write(makefile) f.close() From 9a8d5412e0b584ebb3e19e6747391d58ac54c74f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 9 Jun 2015 16:55:58 +0200 Subject: [PATCH 17/36] prepare.py: fix dummy libraries generation --- linphone.xcodeproj/project.pbxproj | 4 ---- prepare.py | 24 ++++++++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 7cf06a6bf..c47341102 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -892,7 +892,6 @@ /* Begin PBXFileReference section */ 045B5CB218D72E9A0088350C /* libbzrtp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbzrtp.a; path = "liblinphone-sdk/apple-darwin/lib/libbzrtp.a"; sourceTree = ""; }; - 15017E6F1773578400784ACB /* libxml2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libxml2.a; path = "liblinphone-sdk/apple-darwin/lib/libxml2.a"; sourceTree = ""; }; 152F22331B15E83B008C0621 /* libilbcrfc3951.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbcrfc3951.a; path = "liblinphone-sdk/apple-darwin/lib/libilbcrfc3951.a"; sourceTree = ""; }; 152F22351B15E889008C0621 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; 1560821E18EEF26100765332 /* libmsopenh264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsopenh264.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsopenh264.a"; sourceTree = ""; }; @@ -952,7 +951,6 @@ 22276E8213C73D3100210156 /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswscale.a; path = "liblinphone-sdk/apple-darwin/lib/libswscale.a"; sourceTree = ""; }; 22276E8613C73D8A00210156 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; 22276E8813C73DC000210156 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; - 223148E31178A08200637D6A /* libilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbc.a; path = "liblinphone-sdk/apple-darwin/lib/libilbc.a"; sourceTree = ""; }; 223148E51178A09900637D6A /* libmsilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsilbc.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsilbc.a"; sourceTree = ""; }; 2234C8E715EE2F7F00E18E83 /* chat_message_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_delivered.png; path = Resources/chat_message_delivered.png; sourceTree = ""; }; 2234C8E815EE2F7F00E18E83 /* chat_message_not_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_not_delivered.png; path = Resources/chat_message_not_delivered.png; sourceTree = ""; }; @@ -2289,7 +2287,6 @@ F03A9B9718C0DB6F00C4D7FE /* libc++.dylib */, F0BB8C111936240300974404 /* libcunit.a */, 220FAD2910765B400068D98F /* libgsm.a */, - 223148E31178A08200637D6A /* libilbc.a */, 2211DB911475562600DEE054 /* liblinphone.a */, F0BB8C0F193623F200974404 /* liblinphonetester.a */, 22405EE916006F0700B92522 /* libmediastreamer_base.a */, @@ -2319,7 +2316,6 @@ D30BF33216A427BC00AF0026 /* libtunnel.a */, 7066FC0B13E830E400EFC6DC /* libvpx.a */, 22AA8AFB13D7125500B30535 /* libx264.a */, - 15017E6F1773578400784ACB /* libxml2.a */, F0B89C2118DC89E30050B60E /* MediaPlayer.framework */, D37DC7171594AF3400B2A5EB /* MessageUI.framework */, 226EF06B15FA256B005865C7 /* MobileCoreServices.framework */, diff --git a/prepare.py b/prepare.py index a46a8f66a..0f69e7343 100755 --- a/prepare.py +++ b/prepare.py @@ -139,14 +139,15 @@ def warning(platforms): def extract_libs_list(): l = [] - regex = re.compile("lib\S+\.a") + # name = libspeexdsp.a; path = "liblinphone-sdk/apple-darwin/lib/libspeexdsp.a"; sourceTree = ""; }; + regex = re.compile("name = (lib(\S+)\.a); path = \"liblinphone-sdk/apple-darwin/") f = open('linphone.xcodeproj/project.pbxproj', 'r') lines = f.readlines() f.close() for line in lines: m = regex.search(line) if m is not None: - l += [m.group(0)] + l += [m.group(1)] return list(set(l)) @@ -166,7 +167,7 @@ def main(argv=None): dest='list_cmake_variables') argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ 'x86_64', 'devices'], - help="The platform to build for (default is 'x84_64 devices'). Space separated" + help="The platform to build for (default is 'x86_64 devices'). Space separated" " architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) args, additional_args = argparser.parse_known_args() @@ -276,7 +277,7 @@ def main(argv=None): makefile = """ archs={archs} packages={packages} -libs={libs} +libs_list={libs_list} LINPHONE_IPHONE_VERSION=$(shell git describe --always) .PHONY: all @@ -333,9 +334,15 @@ libs: $(addprefix all-,$(archs)) echo "[$$all_archs] Mixing `basename $$archive` in $$destpath"; \\ lipo -create $$all_paths -output $$destpath; \\ done && \\ - for lib in $$libs ; do \\ - if ! test -f liblinphone-sdk/apple-darwin/lib/$$lib ; then \\ - cp -f submodules/binaries/libdummy.a liblinphone-sdk/apple-darwin/lib/$$lib ; \\ + for lib in {libs_list} ; do \\ + if [ $${{lib:0:5}} = "libms" ] ; then \\ + library_path=liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/$$lib ; \\ + else \\ + library_path=liblinphone-sdk/apple-darwin/lib/$$lib ; \\ + fi ; \\ + if ! test -f $$library_path ; then \\ + echo "[$$all_archs] Generating dummy $$lib static library." ; \\ + cp -f submodules/binaries/libdummy.a $$library_path ; \\ fi \\ done @@ -382,7 +389,8 @@ help: @echo "" @echo " * sdk : re-add all generated libraries to the SDK. Use this only after a full build." @echo " * libs : after a rebuild of a subpackage, will mix the new libs in liblinphone-sdk/apple-darwin directory" -""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], arch_targets=arch_targets, packages=' '.join(packages), libs=' '.join(libs_list), multiarch=multiarch) +""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], + arch_targets=arch_targets, packages=' '.join(packages), libs_list=' '.join(libs_list), multiarch=multiarch) f = open('Makefile', 'w') f.write(makefile) f.close() From 3933d9639f2a7b01c6aa30e5ff3664210bcd6ee1 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 9 Jun 2015 17:56:40 +0200 Subject: [PATCH 18/36] libdummy: add arm64 architecture --- submodules/binaries/dummy.c | 6 ++++++ submodules/binaries/libdummy.a | Bin 7684 -> 33420 bytes 2 files changed, 6 insertions(+) create mode 100644 submodules/binaries/dummy.c diff --git a/submodules/binaries/dummy.c b/submodules/binaries/dummy.c new file mode 100644 index 000000000..bf722ecc4 --- /dev/null +++ b/submodules/binaries/dummy.c @@ -0,0 +1,6 @@ +//regenerate libdummy.a using: +// for arch in arm64 armv7 i386 x86_64; do +// clang -c dummy.c -o dummy-$arch.a -arch $arch +// done +// lipo -create -output libdummy.a dummy-*.a +void dummy_does_nothing() {} diff --git a/submodules/binaries/libdummy.a b/submodules/binaries/libdummy.a index a4910d080da86dbecac03dec5e130d83142cc4ac..7f9f9467f00ebfab864746992397cd43ed1b64f1 100644 GIT binary patch literal 33420 zcmeI5y=&7!7{@Pd?VGjDprGK8p@L(F4jmj?RIK1ow1SHqX_A^i-e`WsRvbDBf`g-f zhNC!$;O3xC;y>W%<{%E$=llEJrHM2c3sr~D1JAwXx#upQO!r*w?(P1|SI)UH(+Sg2 z=kk{2E?F{@>$VlFI#N|z&?)Ek)b_-ZS+i5S$+Bs#ZON=D0s#m>00Izz00bZa0SG_< z0uX?}e?s8h_b>Zl;qPo6p9TWHYHkHv$y@eN?Bz^tFK?Z zvwl!lDfU<3p(|r)P$8|(TdGKeo1RYVBbJ_(+8`Qd-V)VMny#7liawVfMQ%U-eD{rY zRR6i?#Fw`lja^@ERXV=eN~*Qyy`%W14+J0p0SG_<0uX=z1Rwwb2teRp5qO`i|8utS zpRRee9)GTNZ^6{$oas_r2d6FliT)HI`4DVkJ;ns&S29dYKz8FwOyqA+Y(SrTUurel z#Zuz8oA+zYviCQxs6EPLC=^2e$^2<9OBP57Q&mWzE8bVCesinXsANsv_s1+Q2FvA; ze+&LXRdI;;)zhXy@r&g!{+i{-62Djt0gN!Qz%zX1I9umVhvMjin=ZGL&*f((CZC#> z=6&Au#g9zl@8MQv^N&U@pX%1l#>~g%xEm+2vLjX^3J3%s009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOL~CPC)zrc6dMCA6BA0_q+-PQxom~KTAu8C$g6;q#h3T z?Bo7_XdZh1zt>;i27S-j0F8ISG(8`Xo+PlF2&}IC^hFy`<#o%okKKDdKy!)O=iAzc zmDi*G;~6v7r3X<|{OuliJ!!NTVh?f%KmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P(2G0loic=l|W5sm`(M{Qas9#}~4??%_X7WKy<7c|7YM?}i`duK(WtUH?62{4*b= zR$i7pfNE~5)K@QCgAsVSMSWubocg(%LcA_gB9qPxt7;~Z#0UFxGLaZbr&V=i&iGWXro|>s9v=;U7b zAVd!zkXe*a`$ahK2Lv zU$^f&K~T`bpxo)kLluJc%Y1i{ei-(xKt!M!9F~4*r)l-Vxq7pcrcLfWG1;v1EsVnc z4EUUct!Z0T8zX1vC9OiJb`18XtOiD_VBuz+x~Aofidn}~FR^VA7!CybREs(Dd^u~B z%z7i64vOKdBa=nbChB^uQ{t9d@il=)wFye+c={YE2pi+ z*R=8DV@LNnLs)Avj+zrw6@P~8KL_Jr=-F(oFhf7)V;n&LohXxS>w>0EjGA6KQ!qO) zF2Ptud0%2A;0JRN(t%OdbJld){kU%1i!THCQ7TpnG#falo-qp$B#X(Ic8%R**C19w#TCYj6q8%iU8 z5LB&wiJI~@N=Ov(RFuD?E9roovJ#&%3pF!tmW^6Tug6WJQOgy~IR5VHv{5Mx6)hDv z8`-jvZfgz?6h-|C@5#}2DA7_Vql z)J!a?ZqAjkn+;_W!?8pxo!Fvo&gy0%ui~?1I~+@!GnFmkzwAC>Jb!l38$py zdCoeHK1**F;^QehVXtv-OQ3#B*113MKczi~U8Ts4!h_WHLKfhaqoW@D&S7_|x+J`E zbi`xag?J?wfOF@v1mTtIU`Sp_{e)LGxfsG{iE~^%&b)FE=a>D9IEp;MJ|`a~uT0DH z6oHlQH2rv#ymF_HA4| zUU?cAJQixcbMfbu?@5f00$_OY$}fOHUU@@eOuEj+pI6=kh6;?Z?3;JVF_>8AQ%Qb1 z2fduU@;3Z&<&``^p76@Yi&vUUO)RZ!LBxX*=Hg0N#+uSSTaFr+d?cQ`onU| zWBf^lxW@gB-0~M$=N_>bZn*%jOpIoh<-Rg8;xTS2IV`U?JMSyW3&|%Laq6oi>Z)B& z^W8;M7=DFs)DEv)CGCRTSF#WL&x47KJs1^*5yR~=FUq#s=F@A?1j3cB2!;1rbV%v+?0{G!|w?>SMC=SLQA3wY}&_?O_ z&jI}Kx?3Yg2qg%H*WKDC8M&MOca6Rr$Ol74n`_&`JP9b=`*w#)5)ht;y&D zd3mqaPX5oX){4X1MwXfYS$TqW8?aVyc?l46lex;I<@R9-?@-z6=Y8P0@hK zHx})=6nb%GID>b54kx8%U)Edh*{)C6f6g`TbKpYPZ^}CNiVf19PORdC;&adT4}l9| AVE_OC From c7437b3ccd1fecbd161f1dcdb649035a36631327 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 15 Jun 2015 14:52:54 +0200 Subject: [PATCH 19/36] update libvpx repo because http://git.chromium.org/webm/libvpx.git is no longuer available --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 8cfc3ac8c..e75d7c5ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,7 +32,7 @@ url = git://git.linphone.org/msx264.git [submodule "submodules/externals/libvpx"] path = submodules/externals/libvpx - url = http://git.chromium.org/webm/libvpx.git + url = https://github.com/webmproject/libvpx ignore = dirty [submodule "submodules/bzrtp"] path = submodules/bzrtp From d09094223d25995aacf161a01656d9a71972668f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 11 Jun 2015 17:09:12 +0200 Subject: [PATCH 20/36] coding style: experimental use of a clang-format git pre-commit hook to force code convention --- .clang-format | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ .git-pre-commit | 50 ++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + prepare.py | 10 ++++++++ 4 files changed, 125 insertions(+) create mode 100644 .clang-format create mode 100755 .git-pre-commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..769b266b1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,64 @@ +--- +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: true +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: false +IndentFunctionDeclarationAfterType: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Always +... diff --git a/.git-pre-commit b/.git-pre-commit new file mode 100755 index 000000000..c0fb0bd9b --- /dev/null +++ b/.git-pre-commit @@ -0,0 +1,50 @@ +#!/bin/bash + +# This hook purpose is to keep coding style consistent between all developers +# It is automatically installed in .git/hooks folder by cmake on first run. + +# From https://github.com/tatsuhiro-t/nghttp2/blob/master/pre-commit + +function invalid-format-detected { + cat git-clang-format.diff + echo "*****************" + echo "$0: Invalid coding style detected (see git-clang-format.diff for issues). Please correct it using one of the following:" + echo "1) Apply patch located at git-clang-format.diff using:" + echo " cd $(git rev-parse --show-toplevel) && $1" + echo "2) Use clang-format to correctly format source code using:" + echo " $2" + echo "3) Reformat these lines manually." + echo "*** Aborting commit.***" + exit 1 +} +function git-clang-format-diffing { + format_diff=$(which git-clang-format) + format_diff_options="--style=file" + + #only diffing commited files, ignored staged one + $format_diff $format_diff_options --diff $(git --no-pager diff --cached --name-only) > git-clang-format.diff + + if ! grep -q -E '(no modified files to format|clang-format did not modify any files)' git-clang-format.diff; then + invalid-format-detected "git apply git-clang-format.diff" "clang-format $format_diff_options -i " + fi +} + +function clang-format-diff-diffing { + format_diff=$(find /usr/bin/ -name 'clang-format-diff*' -type f | tail -n1) + format_diff_options="-style file" + + git diff-index --cached --diff-filter=ACMR -p HEAD -- | $format_diff $format_diff_options -p1 > git-clang-format.diff + if [ -s git-clang-format.diff ]; then + invalid-format-detected "patch -p0 < git-clang-format.diff" "${format_diff/-diff/} $format_diff_options -i " + fi +} + +if which git-clang-format &>/dev/null; then + git-clang-format-diffing $@ +elif [ ! -z "$(find /usr/bin/ /usr/local/bin/ /opt/bin/ -name 'clang-format-diff*' -type f 2>/dev/null)" ]; then + # Warning! We need at least version 1.6... + clang-format-diff-diffing $@ +else + echo "$0: Please install clang-format (coding style checker) - could not find git-clang-format nor clang-format-diff in PATH." + exit 1 +fi diff --git a/.gitignore b/.gitignore index 8b74a154e..fc80e3d8f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ test-reports WORK Makefile OUTPUT +git-clang-format.diff diff --git a/prepare.py b/prepare.py index 0f69e7343..8e9cffca0 100755 --- a/prepare.py +++ b/prepare.py @@ -151,6 +151,14 @@ def extract_libs_list(): return list(set(l)) +def install_git_hook(): + git_hook_path = ".git{sep}hooks{sep}pre-commit".format(sep=os.sep) + if os.path.isdir(".git{sep}hooks".format(sep=os.sep)) and not os.path.isfile(git_hook_path): + print("Installing Git pre-commit hook") + shutil.copyfile(".git-pre-commit", git_hook_path) + os.chmod(git_hook_path, 0755) + + def main(argv=None): if argv is None: argv = sys.argv @@ -171,6 +179,8 @@ def main(argv=None): " architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) args, additional_args = argparser.parse_known_args() + install_git_hook() + selected_platforms = [] for platform in args.platform: if platform == 'all': From c501f5985971b7eb90670589c9bc63badcc7670c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 10 Jun 2015 15:08:58 +0200 Subject: [PATCH 21/36] prepare.py: separate --debug and --debug-verbose options --- prepare.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/prepare.py b/prepare.py index 8e9cffca0..f725375ab 100755 --- a/prepare.py +++ b/prepare.py @@ -167,7 +167,9 @@ def main(argv=None): argparser.add_argument( '-c', '-C', '--clean', help="Clean a previous build instead of preparing a build.", action='store_true') argparser.add_argument( - '-d', '--debug', help="Prepare a debug build.", action='store_true') + '-d', '--debug', help="Prepare a debug build, eg. add debug symbols and use no optimizations.", action='store_true') + argparser.add_argument( + '-dv', '--debug-verbose', help="Activate ms_debug logs.", action='store_true') argparser.add_argument( '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') argparser.add_argument('-L', '--list-cmake-variables', @@ -201,7 +203,7 @@ def main(argv=None): if args.clean: target.clean() else: - if args.debug: + if args.debug_verbose: additional_args += ["-DENABLE_DEBUG_LOGS=YES"] retcode = prepare.run( target, args.debug, False, args.list_cmake_variables, args.force, additional_args) From 06375f58af468d76cf1b5eb48f9934a059c70743 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 10 Jun 2015 13:38:20 +0200 Subject: [PATCH 22/36] filetransfer: rework file transfer to use latest API --- Classes/Base.lproj/ChatRoomViewController.xib | 61 +- Classes/ChatRoomTableViewController.h | 1 - Classes/ChatRoomTableViewController.m | 17 +- Classes/ChatRoomViewController.h | 9 +- Classes/ChatRoomViewController.m | 251 +------- Classes/ChatTableViewController.m | 59 +- Classes/ImageSharing.h | 52 -- Classes/ImageSharing.m | 176 ------ Classes/LinphoneCoreSettingsStore.m | 2 +- Classes/LinphoneManager.h | 13 +- Classes/LinphoneManager.m | 33 +- .../LinphoneUI/Base.lproj/UIChatRoomCell.xib | 44 +- Classes/LinphoneUI/UIChatCell.m | 11 +- Classes/LinphoneUI/UIChatRoomCell.h | 7 +- Classes/LinphoneUI/UIChatRoomCell.m | 543 ++++++++++-------- Classes/Utils/FileTransferDelegate.h | 20 + Classes/Utils/FileTransferDelegate.m | 207 +++++++ Classes/Utils/Utils.m | 5 +- KifTests/ChatTester.m | 135 ++++- Resources/linphonerc | 2 +- Resources/linphonerc~ipad | 2 +- linphone.xcodeproj/project.pbxproj | 14 +- submodules/belle-sip | 2 +- submodules/linphone | 2 +- submodules/msopenh264 | 2 +- 25 files changed, 808 insertions(+), 862 deletions(-) delete mode 100644 Classes/ImageSharing.h delete mode 100644 Classes/ImageSharing.m create mode 100644 Classes/Utils/FileTransferDelegate.h create mode 100644 Classes/Utils/FileTransferDelegate.m diff --git a/Classes/Base.lproj/ChatRoomViewController.xib b/Classes/Base.lproj/ChatRoomViewController.xib index 92c0c0cac..58c8256f6 100644 --- a/Classes/Base.lproj/ChatRoomViewController.xib +++ b/Classes/Base.lproj/ChatRoomViewController.xib @@ -1,31 +1,26 @@ - + - + - - - - - @@ -90,46 +85,11 @@ - - + @@ -235,17 +195,6 @@ - @@ -264,16 +213,12 @@ - - - - diff --git a/Classes/ChatRoomTableViewController.h b/Classes/ChatRoomTableViewController.h index afc1c75fa..f8e317dca 100644 --- a/Classes/ChatRoomTableViewController.h +++ b/Classes/ChatRoomTableViewController.h @@ -23,7 +23,6 @@ @protocol ChatRoomDelegate -- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg; - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url; - (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url; diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 88b4d24f9..2cc654e1e 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -63,6 +63,16 @@ if( !chatRoom ) return; [self clearMessageList]; self->messageList = linphone_chat_room_get_history(chatRoom, 0); + + // also append transient upload messages because they are not in history yet! + for (FileTransferDelegate *ftd in [[LinphoneManager instance] fileTransferDelegates]) { + if (linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(ftd.message)) == + linphone_chat_room_get_peer_address(chatRoom) && + linphone_chat_message_is_outgoing(ftd.message)) { + LOGI(@"Appending transient upload message %p", ftd.message); + self->messageList = ms_list_append(self->messageList, ftd.message); + } + } } - (void)reloadData { @@ -76,9 +86,10 @@ messageList = ms_list_append(messageList, linphone_chat_message_ref(chat)); int pos = ms_list_size(messageList) - 1; - [self.tableView beginUpdates]; - [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:pos inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; - [self.tableView endUpdates]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0]; + [self.tableView beginUpdates]; + [self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade]; + [self.tableView endUpdates]; } - (void)updateChatEntry:(LinphoneChatMessage*)chat { diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index ef59ea284..763018847 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -24,14 +24,12 @@ #import "ChatRoomTableViewController.h" #import "HPGrowingTextView.h" #import "ImagePickerViewController.h" -#import "ImageSharing.h" #import "OrderedDictionary.h" #include "linphone/linphonecore.h" -@interface ChatRoomViewController : UIViewController { +@interface ChatRoomViewController : UIViewController { LinphoneChatRoom *chatRoom; - ImageSharing *imageSharing; OrderedDictionary *imageQualities; BOOL scrollOnGrowingEnabled; BOOL composingVisible; @@ -54,17 +52,12 @@ @property (strong, nonatomic) IBOutlet UIView *composeIndicatorView; @property (nonatomic, strong) IBOutlet UIButton* pictureButton; -@property (nonatomic, strong) IBOutlet UIButton* cancelTransferButton; -@property (nonatomic, strong) IBOutlet UIProgressView* imageTransferProgressBar; -@property (nonatomic, strong) IBOutlet UIView* transferView; -@property (nonatomic, strong) IBOutlet UIView* waitView; - (IBAction)onBackClick:(id)event; - (IBAction)onEditClick:(id)event; - (IBAction)onMessageChange:(id)sender; - (IBAction)onSendClick:(id)event; - (IBAction)onPictureClick:(id)event; -- (IBAction)onTransferCancelClick:(id)event; - (IBAction)onListTap:(id)sender; - (void)setChatRoom:(LinphoneChatRoom*)room; diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 4c46cd65b..5509d9efa 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -21,20 +21,14 @@ #import "PhoneMainView.h" #import "DTActionSheet.h" #import "UILinphone.h" -//#import "UIAlertView+Blocks.h" #import "DTAlertView.h" - +#import "Utils/FileTransferDelegate.h" #import #import #import "Utils.h" +#import "UIChatRoomCell.h" -@implementation ChatRoomViewController { - /* Message transfer transient storage */ - NSData* upload_data; - size_t upload_bytes_sent; - - NSMutableData* download_data; -} +@implementation ChatRoomViewController @synthesize tableController; @synthesize sendButton; @@ -52,32 +46,23 @@ @synthesize listTapGestureRecognizer; @synthesize listSwipeGestureRecognizer; @synthesize pictureButton; -@synthesize imageTransferProgressBar; -@synthesize cancelTransferButton; -@synthesize transferView; -@synthesize waitView; #pragma mark - Lifecycle Functions - (id)init { - self = [super initWithNibName:@"ChatRoomViewController" bundle:[NSBundle mainBundle]]; - if (self != nil) { - self->scrollOnGrowingEnabled = TRUE; - self->chatRoom = NULL; - self->imageSharing = NULL; - self->listTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onListTap:)]; - self.listSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onListSwipe:)]; - self->imageQualities = [[OrderedDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithFloat:0.9], NSLocalizedString(@"Maximum", nil), - [NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil), - [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; - self->composingVisible = TRUE; - - self->upload_data = nil; - self->upload_bytes_sent = 0; - self->download_data = nil; - } - return self; + self = [super initWithNibName:@"ChatRoomViewController" bundle:[NSBundle mainBundle]]; + if (self != nil) { + self->scrollOnGrowingEnabled = TRUE; + self->chatRoom = NULL; + self->listTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onListTap:)]; + self.listSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onListSwipe:)]; + self->imageQualities = [[OrderedDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithFloat:0.9], NSLocalizedString(@"Maximum", nil), + [NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil), + [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; + self->composingVisible = TRUE; + } + return self; } - (void)dealloc { @@ -168,6 +153,7 @@ static UICompositeViewDescription *compositeDescription = nil; selector:@selector(textComposeEvent:) name:kLinphoneTextComposeEvent object:nil]; + if([tableController isEditing]) [tableController setEditing:FALSE animated:FALSE]; [editButton setOff]; @@ -179,39 +165,16 @@ static UICompositeViewDescription *compositeDescription = nil; BOOL fileSharingEnabled = [[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"] != NULL && [[[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"] length]>0; [pictureButton setEnabled:fileSharingEnabled]; - [waitView setHidden:TRUE]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - if(upload_data || download_data ) { - // TODO: when the API permits it, we should cancel the transfer. - } - [messageField resignFirstResponder]; [self setComposingVisible:FALSE withDelay:0]; // will hide the "user is composing.." message - [[NSNotificationCenter defaultCenter] removeObserver:self - name:UIApplicationDidBecomeActiveNotification - object:nil]; - - [[NSNotificationCenter defaultCenter] removeObserver:self - name:UIKeyboardWillShowNotification - object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:UIKeyboardWillHideNotification - object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:kLinphoneTextReceived - object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:UITextViewTextDidChangeNotification - object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:kLinphoneTextComposeEvent - object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { @@ -298,9 +261,9 @@ static UICompositeViewDescription *compositeDescription = nil; } static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { - ChatRoomViewController* thiz = (__bridge ChatRoomViewController*)ud; - const char*text = linphone_chat_message_get_text(msg); + const char *text = (linphone_chat_message_get_file_transfer_information(msg) != NULL) ? "photo transfer" : linphone_chat_message_get_text(msg); LOGI(@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)); + ChatRoomViewController* thiz = (__bridge ChatRoomViewController*)ud; [thiz.tableController updateChatEntry:msg]; } @@ -332,8 +295,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url { - [waitView setHidden:FALSE]; - DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Choose the image size", nil)]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //UIImage *image = [original_image normalizedImage]; @@ -349,7 +310,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; dispatch_async(dispatch_get_main_queue(), ^{ - [waitView setHidden:TRUE]; [sheet showInView:[PhoneMainView instance].view]; }); }); @@ -482,20 +442,8 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark - Action Functions - (IBAction)onBackClick:(id)event { - if( upload_data != nil || download_data != nil ){ - DTAlertView *alertView = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Cancel transfer?", nil) - message:NSLocalizedString(@"You have a transfer in progress, leaving this view will cancel it. Are you sure?", nil)]; - [alertView addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) - block:nil]; - [alertView addButtonWithTitle:NSLocalizedString(@"Yes", nil) - block:^{ - [self.tableController setChatRoom:NULL]; - [[PhoneMainView instance] popCurrentView]; - }]; - } else { - [self.tableController setChatRoom:NULL]; - [[PhoneMainView instance] popCurrentView]; - } + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; } - (IBAction)onEditClick:(id)event { @@ -573,76 +521,21 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [sheet showInView:[PhoneMainView instance].view]; } -- (IBAction)onTransferCancelClick:(id)event { - if(imageSharing) { - [imageSharing cancel]; - } -} - - #pragma mark ChatRoomDelegate -- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg { - if(self->download_data == nil) { - const char* url = linphone_chat_message_get_external_body_url(msg); - LOGI(@"Content to download: %s", url); - - if( url == nil ) return FALSE; - - download_data = [[NSMutableData alloc] init]; - - linphone_chat_message_set_user_data(msg, (void*)CFBridgingRetain(self)); - linphone_chat_message_start_file_download(msg,NULL,NULL); - - [messageView setHidden:TRUE]; - [transferView setHidden:FALSE]; - return TRUE; - } - return FALSE; -} - - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{ - if( self->upload_data == nil) { - LinphoneContent* content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom)); - self->upload_data = UIImageJPEGRepresentation(image, 1.0); - linphone_content_set_type(content, "image"); - linphone_content_set_subtype(content, "jpeg"); - linphone_content_set_name(content, [[NSString stringWithFormat:@"%li-%f.jpg", (long)[image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); - linphone_content_set_size(content, [self->upload_data length]); - - LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, content); - linphone_chat_message_set_user_data(message, (void*)CFBridgingRetain(self)); - - if ( url ) { - // internal url is saved in the appdata for display and later save - [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message]; - } - - // TODO: in the user data, we should maybe put a standalone delegate alloced and retained, instead of self. - // This will make sure that when receiving a memory alert or go to another view, we still send the message - linphone_chat_room_send_message2(chatRoom, message, message_status, (void*)CFBridgingRetain(self)); - - [tableController addChatEntry:linphone_chat_message_ref(message)]; - [tableController scrollToBottom:true]; - [messageView setHidden:TRUE]; - [transferView setHidden:FALSE]; - return TRUE; - } - return FALSE; + FileTransferDelegate * fileTransfer = [[FileTransferDelegate alloc] init]; + [[[LinphoneManager instance] fileTransferDelegates] addObject:fileTransfer]; + [fileTransfer upload:image withURL:url forChatRoom:chatRoom]; + [tableController addChatEntry:linphone_chat_message_ref(fileTransfer.message)]; + [tableController scrollToBottom:true]; + return TRUE; } - (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url { [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] withInternalURL:nil]; } -#pragma mark ImageSharingDelegate - -- (void)imageSharingAborted:(ImageSharing*)aimageSharing { - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - imageSharing = nil; -} - #pragma mark ImagePickerDelegate - (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info { @@ -659,94 +552,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [self chooseImageQuality:image url:url]; } -#pragma mark - LinphoneChatContentTransferDelegate - -- (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent { - [imageTransferProgressBar setProgress:percent/100.0f]; -} - -- (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size { - if( self->upload_data ){ - size_t to_send = *size; - size_t remaining = [upload_data length] - self->upload_bytes_sent; - - LOGI(@"Asking %ld bytes, sent %ld of %d, %ld remaining", to_send, self->upload_bytes_sent, [upload_data length], remaining); - - if( remaining < to_send ) to_send = remaining; - - @try { - [upload_data getBytes:(void*)buffer range:NSMakeRange(upload_bytes_sent, to_send)]; - upload_bytes_sent += to_send; - *size = to_send; - } - @catch (NSException *exception) { - LOGE(@"Exception: %@", exception); - } - - - if( to_send == 0 || upload_bytes_sent == [upload_data length] ){ - LOGI(@"Upload finished, cleanup.."); - upload_data = nil; - upload_bytes_sent = 0; - - // update UI - dispatch_async(dispatch_get_main_queue(), ^{ - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - }); - } - - } else { - LOGE(@"Error: no upload data in progress!"); - } -} - -- (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size { - if( download_data ){ - LOGI(@"Receiving data for %s : %zu bytes, already got %d of %zu", linphone_content_get_name(content), size, [download_data length], linphone_content_get_size(content)); - - if( size != 0 ){ - [download_data appendBytes:buffer length:size]; - } - - if( size == 0 && [download_data length] == linphone_content_get_size(content)){ - - LOGI(@"Transfer is finished, save image and update chat"); - - dispatch_async(dispatch_get_main_queue(), ^{ - //we're finished, save the image and update the message - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - - UIImage* image = [UIImage imageWithData:download_data]; - - download_data = nil; - - [[LinphoneManager instance].photoLibrary - writeImageToSavedPhotosAlbum:image.CGImage - orientation:(ALAssetOrientation)[image imageOrientation] - completionBlock:^(NSURL *assetURL, NSError *error){ - if (error) { - LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); - - UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil) - message:NSLocalizedString(@"Cannot write image to photo library", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Ok",nil) - otherButtonTitles:nil ,nil]; - [errorAlert show]; - return; - } - LOGI(@"Image saved to [%@]", [assetURL absoluteString]); - [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:msg]; - [tableController updateChatEntry:msg]; - }]; - - }); - } - } -} - #pragma mark - Keyboard Event Functions - (void)keyboardWillHide:(NSNotification *)notif { diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index 23097283e..c5f38c70a 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -64,43 +64,44 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo LinphoneChatMessage* last_elem_message = linphone_chat_room_get_user_data(elem); if( last_new_message && last_elem_message ){ - time_t new = linphone_chat_message_get_time(last_new_message); - time_t old = linphone_chat_message_get_time(last_elem_message); - if ( new < old ) return 1; - else if ( new > old) return -1; - } - return 0; + time_t new = linphone_chat_message_get_time(last_new_message); + time_t old = linphone_chat_message_get_time(last_elem_message); + if (new < old) + return 1; + else if (new > old) + return -1; + } + return 0; } - (MSList*)sortChatRooms { - MSList* sorted = nil; - MSList* unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]); - MSList* iter = unsorted; + MSList *sorted = nil; + MSList *unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]); + MSList *iter = unsorted; - while (iter) { - // store last message in user data - MSList* history = linphone_chat_room_get_history(iter->data, 1); - LinphoneChatMessage* last_msg = history? history->data : NULL; - if( last_msg ){ - linphone_chat_room_set_user_data(iter->data, linphone_chat_message_ref(last_msg)); - } - ms_list_free_with_data(history, (void (*)(void *))linphone_chat_message_unref); + while (iter) { + // store last message in user data + LinphoneChatRoom *chat_room = iter->data; + MSList *history = linphone_chat_room_get_history(iter->data, 1); + assert(ms_list_size(history) <= 1); + LinphoneChatMessage *last_msg = history ? history->data : NULL; + if (last_msg) { + linphone_chat_message_ref(last_msg); + linphone_chat_room_set_user_data(chat_room, last_msg); + } + sorted = ms_list_insert_sorted(sorted, chat_room, (MSCompareFunc)sorted_history_comparison); - sorted = ms_list_insert_sorted(sorted, - iter->data, - (MSCompareFunc)sorted_history_comparison); - - iter = iter->next; - } - return sorted; + iter = iter->next; + } + return sorted; } static void chatTable_free_chatrooms(void *data){ - LinphoneChatMessage* lastMsg = linphone_chat_room_get_user_data(data); - if( lastMsg ){ - linphone_chat_message_unref(lastMsg); - linphone_chat_room_set_user_data(data, NULL); - } + LinphoneChatMessage *lastMsg = linphone_chat_room_get_user_data(data); + if (lastMsg) { + linphone_chat_message_unref(lastMsg); + linphone_chat_room_set_user_data(data, NULL); + } } - (void)loadData { diff --git a/Classes/ImageSharing.h b/Classes/ImageSharing.h deleted file mode 100644 index e222e747d..000000000 --- a/Classes/ImageSharing.h +++ /dev/null @@ -1,52 +0,0 @@ -/* ImageSharing.h - * - * Copyright (C) 2012 Belledonne Comunications, Grenoble, France - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#import - -@class ImageSharing; - -@protocol ImageSharingDelegate - -- (void)imageSharingProgress:(ImageSharing*)imageSharing progress:(float)progress; -- (void)imageSharingAborted:(ImageSharing*)imageSharing; -- (void)imageSharingError:(ImageSharing*)imageSharing error:(NSError *)error; -- (void)imageSharingUploadDone:(ImageSharing*)imageSharing url:(NSURL*)url; -- (void)imageSharingDownloadDone:(ImageSharing*)imageSharing image:(UIImage *)image; - -@end - -@interface ImageSharing : NSObject { -@private - NSInteger totalBytesExpectedToRead; - id delegate; - NSInteger statusCode; -} - -+ (id)newImageSharingUpload:(NSURL*)url image:(UIImage*)image delegate:(id)delegate userInfo:(id)userInfo; -+ (id)newImageSharingDownload:(NSURL*)url delegate:(id)delegate userInfo:(id)userInfo; - -- (void)cancel; - -@property (nonatomic, strong) id userInfo; - -@property (nonatomic, readonly) BOOL upload; -@property (nonatomic, readonly) NSMutableData* data; -@property (nonatomic, readonly) NSURLConnection* connection; - -@end diff --git a/Classes/ImageSharing.m b/Classes/ImageSharing.m deleted file mode 100644 index 3ebee1b80..000000000 --- a/Classes/ImageSharing.m +++ /dev/null @@ -1,176 +0,0 @@ -/* ImageSharing.m - * - * Copyright (C) 2012 Belledonne Comunications, Grenoble, France - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#import "ImageSharing.h" -#import "Utils.h" -#import "LinphoneManager.h" - -@implementation ImageSharing - -@synthesize connection; -@synthesize data; -@synthesize upload; -@synthesize userInfo; - -#pragma mark - Lifecycle Functions - -+ (id)newImageSharingUpload:(NSURL*)url image:(UIImage*)image delegate:(id)delegate userInfo:(id)auserInfo{ - ImageSharing *imgs = [[ImageSharing alloc] init]; - if(imgs != nil) { - imgs.userInfo = auserInfo; - imgs->upload = TRUE; - imgs->delegate = delegate; - imgs->data = [[NSMutableData alloc] init]; - if(delegate) { - [delegate imageSharingProgress:imgs progress:0]; - } - [imgs uploadImageTo:url image:image]; - } - return imgs; -} - -+ (id)newImageSharingDownload:(NSURL*)url delegate:(id)delegate userInfo:(id)auserInfo{ - ImageSharing *imgs = [[ImageSharing alloc] init]; - if(imgs != nil) { - imgs.userInfo = auserInfo; - imgs->upload = FALSE; - imgs->delegate = delegate; - imgs->data = [[NSMutableData alloc] init]; - if(delegate) { - [delegate imageSharingProgress:imgs progress:0]; - } - [imgs downloadImageFrom:url]; - } - return imgs; -} - - - -#pragma mark - - -- (void)cancel { - [connection cancel]; - LOGI(@"File transfer interrupted by user"); - if(delegate) { - [delegate imageSharingAborted:self]; - } -} - - -- (void)downloadImageFrom:(NSURL*)url { - LOGI(@"downloading [%@]", [url absoluteString]); - - NSURLRequest* request = [NSURLRequest requestWithURL:url - cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:60.0]; - - connection = [[NSURLConnection alloc] initWithRequest:request delegate: self]; -} - - -- (void)uploadImageTo:(NSURL*)url image:(UIImage*)image { - LOGI(@"downloading [%@]", [url absoluteString]); - // setting up the request object now - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; - [request setURL:url]; - [request setHTTPMethod:@"POST"]; - - /* - add some header info now - we always need a boundary when we post a file - also we need to set the content type - - You might want to generate a random boundary.. this is just the same - as my output from wireshark on a valid html post - */ - NSString *boundary = @"---------------------------14737809831466499882746641449"; - NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; - [request addValue:contentType forHTTPHeaderField: @"Content-Type"]; - - /* - now lets create the body of the post - */ - NSMutableData *body = [NSMutableData data]; - NSString *imageName = [NSString stringWithFormat:@"%lu-%f.jpg", (unsigned long)[image hash],[NSDate timeIntervalSinceReferenceDate]]; - [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n",imageName] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)]]; - [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [request setHTTPBody:body]; - - connection = [[NSURLConnection alloc] initWithRequest:(NSURLRequest *)request delegate:self]; -} - - -#pragma mark - NSURLConnectionDelegate - -- (void)connection:(NSURLConnection *)aconnection didFailWithError:(NSError *)error { - if(delegate) { - [delegate imageSharingError:self error:error]; - } -} - -- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { - if(upload && delegate) { - [delegate imageSharingProgress:self progress:(float)totalBytesWritten/(float)totalBytesExpectedToWrite]; - } -} - -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)adata { - [data appendData:adata]; - if(!upload && delegate) { - [delegate imageSharingProgress:self progress:(float)data.length/(float)totalBytesExpectedToRead]; - } -} - -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response; - statusCode = httpResponse.statusCode; - LOGI(@"File transfer status code [%i]", statusCode); - - if (statusCode == 200 && !upload) { - totalBytesExpectedToRead = (int)[response expectedContentLength]; - } -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - if(statusCode >= 400) { - NSError *error = [NSError errorWithDomain:@"ImageSharing" code:statusCode userInfo:nil]; - if(delegate) { - [delegate imageSharingError:self error:error]; - } - return; - } - if (upload) { - NSString* imageRemoteUrl = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - LOGI(@"File can be downloaded from [%@]", imageRemoteUrl); - if(delegate) { - [delegate imageSharingUploadDone:self url:[NSURL URLWithString:imageRemoteUrl]]; - } - } else { - UIImage* image = [UIImage imageWithData:data]; - LOGI(@"File downloaded"); - if(delegate) { - [delegate imageSharingDownloadDone:self image:image]; - } - } -} - -@end diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 191972865..471fa9d3a 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -693,7 +693,7 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); NSString* sharing_server = [self stringForKey:@"sharing_server_preference"]; [[LinphoneManager instance] lpConfigSetString:sharing_server forKey:@"sharing_server_preference"]; - + linphone_core_set_file_transfer_server(lc, [sharing_server UTF8String]); //Tunnel if (linphone_core_tunnel_available()){ diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 59dba725e..08f868929 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -52,6 +52,8 @@ extern NSString *const kLinphoneBluetoothAvailabilityUpdate; extern NSString *const kLinphoneConfiguringStateUpdate; extern NSString *const kLinphoneGlobalStateUpdate; extern NSString *const kLinphoneNotifyReceived; +extern NSString *const kLinphoneFileTransferSendUpdate; +extern NSString *const kLinphoneFileTransferRecvUpdate; typedef enum _NetworkType { network_none = 0, @@ -98,14 +100,6 @@ struct NetworkReachabilityContext { }; @end -@protocol LinphoneChatContentTransferDelegate - --(void)onProgressReport:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content percent:(int)percent; --(void)onDataRequested:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(char*)buffer withSize:(size_t*)size; --(void)onDataReceived:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(const char*)buffer withSize:(size_t)size; - -@end - typedef struct _LinphoneManagerSounds { SystemSoundID vibrate; } LinphoneManagerSounds; @@ -211,5 +205,6 @@ typedef struct _LinphoneManagerSounds { @property (readonly) BOOL wasRemoteProvisioned; @property (readonly) LpConfig *configDb; @property (readonly) InAppProductsManager *iapManager; -@end +@property(strong, nonatomic) NSMutableArray *fileTransferDelegates; +@end \ No newline at end of file diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index e2e93603e..db9bc07f3 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -68,7 +68,8 @@ NSString *const kLinphoneBluetoothAvailabilityUpdate = @"LinphoneBluetoothAvaila NSString *const kLinphoneConfiguringStateUpdate = @"LinphoneConfiguringStateUpdate"; NSString *const kLinphoneGlobalStateUpdate = @"LinphoneGlobalStateUpdate"; NSString *const kLinphoneNotifyReceived = @"LinphoneNotifyReceived"; - +NSString *const kLinphoneFileTransferSendUpdate = @"LinphoneFileTransferSendUpdate"; +NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpdate"; const int kLinphoneAudioVbrCodecDefaultBitrate=36; /*you can override this from linphonerc or linphonerc-factory*/ @@ -273,6 +274,7 @@ struct codec_name_pref_table codec_pref_table[]={ bluetoothEnabled = FALSE; tunnelMode = FALSE; + _fileTransferDelegates = [[NSMutableArray alloc] init]; pushCallIDs = [[NSMutableArray alloc] init ]; photoLibrary = [[ALAssetsLibrary alloc] init]; @@ -915,29 +917,6 @@ static void linphone_iphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev [(__bridge LinphoneManager*)linphone_core_get_user_data(lc) onNotifyReceived:lc event:lev notifyEvent:notified_event content:body]; } -#pragma mark - FileTransfer functions - -static void linphone_iphone_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) { - id delegate = (__bridge id)linphone_chat_message_get_user_data(message); - LOGI(@"Transfer of %s, incoming data (%d bytes)", linphone_content_get_name(content), size); - [delegate onDataReceived:message forContent:content buffer:buff withSize:size]; -} - -static void linphone_iphone_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ - id delegate = (__bridge id)linphone_chat_message_get_user_data(message); - LOGI(@"Transfer of %s, requesting data (%d bytes)", linphone_content_get_name(content), *size); - [delegate onDataRequested:message forContent:content buffer:buff withSize:size]; -} - -static void linphone_iphone_file_transfer_progress(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total){ - id delegate = (__bridge id)linphone_chat_message_get_user_data(message); - float progress = offset*100.f/total; - LOGI(@"Progress of transfer %s: %d%%", linphone_content_get_name(content), progress); - [delegate onProgressReport:message forContent:content percent:progress]; -} - - - #pragma mark - Message composition start - (void)onMessageComposeReceived:(LinphoneCore*)core forRoom:(LinphoneChatRoom*)room { @@ -1228,11 +1207,7 @@ static LinphoneCoreVTable linphonec_vtable = { .is_composing_received = linphone_iphone_is_composing_received, .configuring_status = linphone_iphone_configuring_status_changed, .global_state_changed = linphone_iphone_global_state_changed, - .notify_received = linphone_iphone_notify_received, - .file_transfer_recv = linphone_iphone_file_transfer_recv, - .file_transfer_send = linphone_iphone_file_transfer_send, - .file_transfer_progress_indication = linphone_iphone_file_transfer_progress - + .notify_received = linphone_iphone_notify_received }; #pragma mark - diff --git a/Classes/LinphoneUI/Base.lproj/UIChatRoomCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatRoomCell.xib index e4a9593a5..9817a998a 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatRoomCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatRoomCell.xib @@ -1,7 +1,8 @@ - + - + + @@ -9,9 +10,11 @@ + + @@ -54,6 +57,7 @@ + + @@ -121,4 +152,9 @@ - \ No newline at end of file + + + + + + diff --git a/Classes/LinphoneUI/UIChatCell.m b/Classes/LinphoneUI/UIChatCell.m index aacc5e510..b80e2cfd7 100644 --- a/Classes/LinphoneUI/UIChatCell.m +++ b/Classes/LinphoneUI/UIChatCell.m @@ -106,11 +106,12 @@ if( last_message ){ - const char* text = linphone_chat_message_get_text(last_message); - const char* url = linphone_chat_message_get_external_body_url(last_message); - // Message - if(url) { - [chatContentLabel setText:@""]; + const char* text = linphone_chat_message_get_text(last_message); + const char* url = linphone_chat_message_get_external_body_url(last_message); + const LinphoneContent *last_content = linphone_chat_message_get_file_transfer_information(last_message); + // Message + if(url||last_content) { + [chatContentLabel setText:@"🗻"]; } else if (text) { NSString *message = [NSString stringWithUTF8String:text]; // shorten long messages diff --git a/Classes/LinphoneUI/UIChatRoomCell.h b/Classes/LinphoneUI/UIChatRoomCell.h index d71a9ec27..9502e5e05 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.h +++ b/Classes/LinphoneUI/UIChatRoomCell.h @@ -24,7 +24,7 @@ #import "UITransparentTVCell.h" #import "UITextViewNoDefine.h" #include "linphone/linphonecore.h" - +#import "FileTransferDelegate.h" @interface UIChatRoomCell : UITransparentTVCell { LinphoneChatMessage* chat; @@ -41,6 +41,8 @@ @property (nonatomic, strong) IBOutlet UIButton* downloadButton; @property (nonatomic, strong) IBOutlet UITapGestureRecognizer* imageTapGestureRecognizer; @property (nonatomic, strong) IBOutlet UITapGestureRecognizer* resendTapGestureRecognizer; +@property (weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress; +@property (weak, nonatomic) IBOutlet UIButton *cancelButton; - (id)initWithIdentifier:(NSString*)identifier; + (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width; @@ -50,7 +52,10 @@ - (IBAction)onDeleteClick:(id)event; - (IBAction)onDownloadClick:(id)event; - (IBAction)onImageClick:(id)event; +- (IBAction)onCancelDownloadClick:(id)sender; - (void)setChatMessage:(LinphoneChatMessage*)message; +- (void)connectToFileDelegate:(FileTransferDelegate*)ftd; + @end diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index 6eaccfcbc..34a341a96 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -28,7 +28,9 @@ #import #include "linphone/linphonecore.h" -@implementation UIChatRoomCell +@implementation UIChatRoomCell { + FileTransferDelegate* ftd; +} @synthesize innerView; @synthesize bubbleView; @@ -56,304 +58,395 @@ static UIFont *CELL_FONT = nil; #pragma mark - Lifecycle Functions - (id)initWithIdentifier:(NSString*)identifier { - if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) { - [[NSBundle mainBundle] loadNibNamed:@"UIChatRoomCell" - owner:self - options:nil]; - imageTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageClick:)]; - [messageImageView addGestureRecognizer:imageTapGestureRecognizer]; + if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) { + [[NSBundle mainBundle] loadNibNamed:@"UIChatRoomCell" + owner:self + options:nil]; + imageTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageClick:)]; + [messageImageView addGestureRecognizer:imageTapGestureRecognizer]; - resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)]; - [dateLabel addGestureRecognizer:resendTapGestureRecognizer]; + resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)]; + [dateLabel addGestureRecognizer:resendTapGestureRecognizer]; - [self addSubview:innerView]; - [deleteButton setAlpha:0.0f]; + [self addSubview:innerView]; + [deleteButton setAlpha:0.0f]; - // shift message box, otherwise it will collide with the bubble - CGRect messageCoords = [messageText frame]; - messageCoords.origin.x += 2; - messageCoords.origin.y += 2; - messageCoords.size.width -= 5; - [messageText setFrame:messageCoords]; - messageText.allowSelectAll = TRUE; - } - return self; + // shift message box, otherwise it will collide with the bubble + CGRect messageCoords = [messageText frame]; + messageCoords.origin.x += 2; + messageCoords.origin.y += 2; + messageCoords.size.width -= 5; + [messageText setFrame:messageCoords]; + messageText.allowSelectAll = TRUE; + } + + return self; } +- (void)dealloc { + [self disconnectFromFileDelegate]; +} #pragma mark - - (void)setChatMessage:(LinphoneChatMessage *)message { - self->chat = message; - [self update]; + if (message != self->chat) { + self->chat = message; + messageImageView.image = nil; + [self disconnectFromFileDelegate]; + for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) { + if (message && + linphone_chat_message_get_storage_id(aftd.message) == linphone_chat_message_get_storage_id(message)) { + LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message, + linphone_chat_message_get_user_data(message)); + [self connectToFileDelegate:aftd]; + break; + } + } + [self update]; + } } + (NSString*)decodeTextMessage:(const char*)text { - NSString* decoded = [NSString stringWithUTF8String:text]; - if( decoded == nil ){ - // couldn't decode the string as UTF8, do a lossy conversion - decoded = [NSString stringWithCString:text encoding:NSASCIIStringEncoding]; - if( decoded == nil ){ - decoded = @"(invalid string)"; - } - } - return decoded; + NSString* decoded = [NSString stringWithUTF8String:text]; + if( decoded == nil ){ + // couldn't decode the string as UTF8, do a lossy conversion + decoded = [NSString stringWithCString:text encoding:NSASCIIStringEncoding]; + if( decoded == nil ){ + decoded = @"(invalid string)"; + } + } + return decoded; } - (void)update { - if(chat == nil) { - LOGW(@"Cannot update chat room cell: null chat"); - return; - } - const char* url = linphone_chat_message_get_external_body_url(chat); - const char* text = linphone_chat_message_get_text(chat); - BOOL is_external = url && (strstr(url, "http") == url); - NSString* localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat]; + if(chat == nil) { + LOGW(@"Cannot update chat room cell: null chat"); + return; + } + const char* url = linphone_chat_message_get_external_body_url(chat); + const char* text = linphone_chat_message_get_text(chat); + BOOL is_external = + (url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(chat); + NSString* localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat]; + // this is an image (either to download or already downloaded) + if (is_external || localImage) { + if(localImage) { + if (messageImageView.image == nil) { + NSURL *imageUrl = [NSURL URLWithString:localImage]; + messageText.hidden = YES; + [messageImageView startLoading]; + __block LinphoneChatMessage *achat = chat; + [[LinphoneManager instance] + .photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + if (achat == self->chat) { // Avoid glitch and scrolling + UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [messageImageView setImage:image]; + [messageImageView setFullImageUrl:asset]; + [messageImageView stopLoading]; + messageImageView.hidden = NO; + }); + } + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } + if (ftd.message != nil) { + _cancelButton.hidden = NO; + _fileTransferProgress.hidden = NO; + downloadButton.hidden = YES; + } else { + _cancelButton.hidden = _fileTransferProgress.hidden = downloadButton.hidden = YES; + } + } else { + messageText.hidden = YES; + messageImageView.hidden = _cancelButton.hidden = _fileTransferProgress.hidden = (ftd.message == nil); + downloadButton.hidden = !_cancelButton.hidden; + } + // simple text message + } else { + [messageText setHidden:FALSE]; + if ( text ){ + NSString* nstext = [UIChatRoomCell decodeTextMessage:text]; - if(is_external && !localImage ) { - [messageText setHidden:TRUE]; - [messageImageView setImage:nil]; - [messageImageView setHidden:TRUE]; - [downloadButton setHidden:FALSE]; + /* We need to use an attributed string here so that data detector don't mess + * with the text style. See http://stackoverflow.com/a/20669356 */ - } else if(localImage) { + NSAttributedString* attr_text = [[NSAttributedString alloc] + initWithString:nstext + attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0], + NSForegroundColorAttributeName:[UIColor darkGrayColor]}]; + messageText.attributedText = attr_text; - NSURL* imageUrl = [NSURL URLWithString:localImage]; + } else { + messageText.text = @""; + } + messageImageView.hidden = YES; + _cancelButton.hidden = _fileTransferProgress.hidden = downloadButton.hidden = YES; + } - [messageText setHidden:TRUE]; - [messageImageView setImage:nil]; - [messageImageView startLoading]; - __block LinphoneChatMessage *achat = chat; - [[LinphoneManager instance].photoLibrary assetForURL:imageUrl resultBlock:^(ALAsset *asset) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) { - if(achat == self->chat) { //Avoid glitch and scrolling - UIImage* image = [[UIImage alloc] initWithCGImage:[asset thumbnail]]; - dispatch_async(dispatch_get_main_queue(), ^{ - [messageImageView setImage:image]; - [messageImageView setFullImageUrl:asset]; - [messageImageView stopLoading]; - }); - } - }); - } failureBlock:^(NSError *error) { - LOGE(@"Can't read image"); - }]; + // Date + time_t chattime = linphone_chat_message_get_time(chat); + NSDate *message_date = (chattime == 0) ? [[NSDate alloc] init] : [NSDate dateWithTimeIntervalSince1970:chattime]; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; + [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; + NSLocale *locale = [NSLocale currentLocale]; + [dateFormatter setLocale:locale]; + [dateLabel setText:[dateFormatter stringFromDate:message_date]]; - [messageImageView setHidden:FALSE]; - [downloadButton setHidden:TRUE]; - } else { - // simple text message - [messageText setHidden:FALSE]; - if ( text ){ - NSString* nstext = [UIChatRoomCell decodeTextMessage:text]; + LinphoneChatMessageState state = linphone_chat_message_get_state(chat); + BOOL outgoing = linphone_chat_message_is_outgoing(chat); - /* We need to use an attributed string here so that data detector don't mess - * with the text style. See http://stackoverflow.com/a/20669356 */ - - NSAttributedString* attr_text = [[NSAttributedString alloc] - initWithString:nstext - attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0], - NSForegroundColorAttributeName:[UIColor darkGrayColor]}]; - messageText.attributedText = attr_text; - - } else { - messageText.text = @""; - } - - [messageImageView setImage:nil]; - [messageImageView setHidden:TRUE]; - - [downloadButton setHidden:TRUE]; - } - - // Date - NSDate* message_date = [NSDate dateWithTimeIntervalSince1970:linphone_chat_message_get_time(chat)]; - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; - [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; - NSLocale *locale = [NSLocale currentLocale]; - [dateFormatter setLocale:locale]; - [dateLabel setText:[dateFormatter stringFromDate:message_date]]; - - LinphoneChatMessageState state = linphone_chat_message_get_state(chat); - BOOL outgoing = linphone_chat_message_is_outgoing(chat); - - if( !outgoing ){ - statusImage.hidden = TRUE; // not useful for incoming chats.. - } else if (state== LinphoneChatMessageStateInProgress) { + if( !outgoing ){ + statusImage.hidden = TRUE; // not useful for incoming chats.. + } else if (state== LinphoneChatMessageStateInProgress) { [statusImage setImage:[UIImage imageNamed:@"chat_message_inprogress.png"]]; - [statusImage setAccessibilityValue:@"in progress"]; + [statusImage setAccessibilityValue:@"in progress"]; statusImage.hidden = FALSE; - } else if (state == LinphoneChatMessageStateDelivered) { + } else if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateFileTransferDone) { [statusImage setImage:[UIImage imageNamed:@"chat_message_delivered.png"]]; - [statusImage setAccessibilityValue:@"delivered"]; + [statusImage setAccessibilityValue:@"delivered"]; statusImage.hidden = FALSE; } else { [statusImage setImage:[UIImage imageNamed:@"chat_message_not_delivered.png"]]; - [statusImage setAccessibilityValue:@"not delivered"]; + [statusImage setAccessibilityValue:@"not delivered"]; statusImage.hidden = FALSE; - NSAttributedString* resend_text = [[NSAttributedString alloc] - initWithString:NSLocalizedString(@"Resend", @"Resend") - attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}]; - [dateLabel setAttributedText:resend_text]; + NSAttributedString* resend_text = [[NSAttributedString alloc] + initWithString:NSLocalizedString(@"Resend", @"Resend") + attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}]; + [dateLabel setAttributedText:resend_text]; } - if( outgoing){ - [messageText setAccessibilityLabel:@"Outgoing message"]; - } else { - [messageText setAccessibilityLabel:@"Incoming message"]; - } - + if( outgoing){ + [messageText setAccessibilityLabel:@"Outgoing message"]; + } else { + [messageText setAccessibilityLabel:@"Incoming message"]; + } } - (void)setEditing:(BOOL)editing { - [self setEditing:editing animated:FALSE]; + [self setEditing:editing animated:FALSE]; } - (void)setEditing:(BOOL)editing animated:(BOOL)animated { - if(animated) { - [UIView beginAnimations:nil context:nil]; - [UIView setAnimationDuration:0.3]; - } - if(editing) { - [deleteButton setAlpha:1.0f]; - } else { - [deleteButton setAlpha:0.0f]; - } - if(animated) { - [UIView commitAnimations]; - } + if(animated) { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.3]; + } + if(editing) { + [deleteButton setAlpha:1.0f]; + } else { + [deleteButton setAlpha:0.0f]; + } + if(animated) { + [UIView commitAnimations]; + } } + (CGSize)viewSize:(LinphoneChatMessage*)chat width:(int)width { - CGSize messageSize; - const char* url = linphone_chat_message_get_external_body_url(chat); - const char* text = linphone_chat_message_get_text(chat); - NSString* messageText = text ? [UIChatRoomCell decodeTextMessage:text] : @""; - if(url == nil) { - if(CELL_FONT == nil) { - CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE]; - } + CGSize messageSize; + const char* url = linphone_chat_message_get_external_body_url(chat); + const char* text = linphone_chat_message_get_text(chat); + NSString* messageText = text ? [UIChatRoomCell decodeTextMessage:text] : @""; + if (url == nil && linphone_chat_message_get_file_transfer_information(chat) == NULL) { + if(CELL_FONT == nil) { + CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE]; + } #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 - if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7){ - messageSize = [messageText - boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX) - options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading) - attributes:@{NSFontAttributeName: CELL_FONT} - context:nil].size; - } else + if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7){ + messageSize = [messageText + boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX) + options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading) + attributes:@{NSFontAttributeName: CELL_FONT} + context:nil].size; + } else #endif - { - messageSize = [messageText sizeWithFont: CELL_FONT - constrainedToSize: CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f) - lineBreakMode: NSLineBreakByTruncatingTail]; - } - } else { - messageSize = CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT); - } - messageSize.height += CELL_MESSAGE_Y_MARGIN; - if(messageSize.height < CELL_MIN_HEIGHT) - messageSize.height = CELL_MIN_HEIGHT; - messageSize.width += CELL_MESSAGE_X_MARGIN; - if(messageSize.width < CELL_MIN_WIDTH) - messageSize.width = CELL_MIN_WIDTH; - return messageSize; + { + messageSize = [messageText sizeWithFont: CELL_FONT + constrainedToSize: CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f) + lineBreakMode: NSLineBreakByTruncatingTail]; + } + } else { + messageSize = CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT); + } + messageSize.height += CELL_MESSAGE_Y_MARGIN; + if(messageSize.height < CELL_MIN_HEIGHT) + messageSize.height = CELL_MIN_HEIGHT; + messageSize.width += CELL_MESSAGE_X_MARGIN; + if(messageSize.width < CELL_MIN_WIDTH) + messageSize.width = CELL_MIN_WIDTH; + return messageSize; } + (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width { - return [UIChatRoomCell viewSize:chatMessage width:width].height; + return [UIChatRoomCell viewSize:chatMessage width:width].height; } #pragma mark - View Functions - (void)layoutSubviews { - [super layoutSubviews]; - if(chat != nil) { - // Resize inner - CGRect innerFrame; - BOOL is_outgoing = linphone_chat_message_is_outgoing(chat); - innerFrame.size = [UIChatRoomCell viewSize:chat width:[self frame].size.width]; - if(!is_outgoing) { // Inverted - innerFrame.origin.x = 0.0f; - innerFrame.origin.y = 0.0f; - } else { - innerFrame.origin.x = [self frame].size.width - innerFrame.size.width; - innerFrame.origin.y = 0.0f; - } - [innerView setFrame:innerFrame]; + [super layoutSubviews]; + if(chat != nil) { + // Resize inner + CGRect innerFrame; + BOOL is_outgoing = linphone_chat_message_is_outgoing(chat); + innerFrame.size = [UIChatRoomCell viewSize:chat width:[self frame].size.width]; + if(!is_outgoing) { // Inverted + innerFrame.origin.x = 0.0f; + innerFrame.origin.y = 0.0f; + } else { + innerFrame.origin.x = [self frame].size.width - innerFrame.size.width; + innerFrame.origin.y = 0.0f; + } + [innerView setFrame:innerFrame]; - CGRect messageFrame = [bubbleView frame]; - messageFrame.origin.y = ([innerView frame].size.height - messageFrame.size.height)/2; - if(!is_outgoing) { // Inverted - UIImage* image = [UIImage imageNamed:@"chat_bubble_incoming"]; - image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(26, 32, 34, 56)]; - [backgroundImage setImage:image]; - messageFrame.origin.y += 5; - } else { - UIImage* image = [UIImage imageNamed:@"chat_bubble_outgoing"]; - image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(14, 15, 25, 40)]; - [backgroundImage setImage:image]; - messageFrame.origin.y -= 5; - } - [bubbleView setFrame:messageFrame]; - } + CGRect messageFrame = [bubbleView frame]; + messageFrame.origin.y = ([innerView frame].size.height - messageFrame.size.height)/2; + if(!is_outgoing) { // Inverted + UIImage* image = [UIImage imageNamed:@"chat_bubble_incoming"]; + image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(26, 32, 34, 56)]; + [backgroundImage setImage:image]; + messageFrame.origin.y += 5; + } else { + UIImage* image = [UIImage imageNamed:@"chat_bubble_outgoing"]; + image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(14, 15, 25, 40)]; + [backgroundImage setImage:image]; + messageFrame.origin.y -= 5; + } + [bubbleView setFrame:messageFrame]; + } } #pragma mark - Action Functions - (IBAction)onDeleteClick:(id)event { - if(chat != NULL) { - UIView *view = [self superview]; - // Find TableViewCell - while(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview]; - if(view != nil) { - UITableView *tableView = (UITableView*) view; - NSIndexPath *indexPath = [tableView indexPathForCell:self]; - [[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath]; - } - } + if(chat != NULL) { + if (ftd.message != nil) { + [ftd cancel]; + } + UIView *view = [self superview]; + // Find TableViewCell + while(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview]; + if(view != nil) { + UITableView *tableView = (UITableView*) view; + NSIndexPath *indexPath = [tableView indexPathForCell:self]; + [[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath]; + } + } } - (IBAction)onDownloadClick:(id)event { - [chatRoomDelegate chatRoomStartImageDownload:chat]; + if (ftd.message == nil) { + ftd = [[FileTransferDelegate alloc] init]; + [[[LinphoneManager instance] fileTransferDelegates] addObject:ftd]; + [self connectToFileDelegate:ftd]; + [ftd download:chat]; + _cancelButton.hidden = NO; + downloadButton.hidden = YES; + } } +- (IBAction)onCancelDownloadClick:(id)sender { + [ftd cancel]; + [self disconnectFromFileDelegate]; + [self update]; +} + + - (IBAction)onImageClick:(id)event { - if(![messageImageView isLoading]) { - ImageViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], ImageViewController); - if(controller != nil) { - CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; - UIImage* fullScreen = [UIImage imageWithCGImage:fullScreenRef]; - [controller setImage:fullScreen]; - } - } + // if(![messageImageView isLoading]) { + // ImageViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] + // changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], ImageViewController); + // if(controller != nil) { + // CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; + // UIImage* fullScreen = [UIImage imageWithCGImage:fullScreenRef]; + // [controller setImage:fullScreen]; + // } + // } + + [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:chat]; } - (IBAction)onResendClick:(id)event { - if( chat == nil ) return; + if( chat == nil ) return; - LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat); - if (state == LinphoneChatMessageStateNotDelivered) { - const char* text = linphone_chat_message_get_text(self->chat); - const char* url = linphone_chat_message_get_external_body_url(self->chat); - NSString* message = text ? [NSString stringWithUTF8String:text] : nil; - NSString* exturl = url ? [NSString stringWithUTF8String:url] : nil; + LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat); + if (state == LinphoneChatMessageStateNotDelivered) { + const char* text = linphone_chat_message_get_text(self->chat); + const char* url = linphone_chat_message_get_external_body_url(self->chat); + NSString* message = text ? [NSString stringWithUTF8String:text] : nil; + NSString* exturl = url ? [NSString stringWithUTF8String:url] : nil; - [self onDeleteClick:nil]; + [self onDeleteClick:nil]; - double delayInSeconds = 0.4; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [chatRoomDelegate resendChat:message withExternalUrl:exturl]; - }); - } + double delayInSeconds = 0.4; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [chatRoomDelegate resendChat:message withExternalUrl:exturl]; + }); + } +} + +#pragma mark - LinphoneFileTransfer Notifications Handling + +- (void)connectToFileDelegate:(FileTransferDelegate*)aftd { + ftd = aftd; + _fileTransferProgress.progress = 0; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onFileTransferSendUpdate:) + name:kLinphoneFileTransferSendUpdate + object:ftd]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onFileTransferRecvUpdate:) + name:kLinphoneFileTransferRecvUpdate + object:ftd]; +} + +- (void)disconnectFromFileDelegate { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + ftd = nil; +} + +- (void)onFileTransferSendUpdate:(NSNotification*)notif { + LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue]; + + if (state == LinphoneChatMessageStateInProgress) { + float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue]; + // When uploading a file, the message file is first uploaded to the server, + // so we are in progress state. Then state goes to filetransfertdone. Then, + // the exact same message is sent to the other chat participant and we come + // back to in progress again. This second time is NOT an upload, so we must + // not update progress! + _fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress); + _fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f); + } else { + [self update]; + } +} +- (void)onFileTransferRecvUpdate:(NSNotification*)notif { + LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue]; + if (state == LinphoneChatMessageStateInProgress) { + float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue]; + _fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress); + _fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f); + } else { + [self update]; + } } @end diff --git a/Classes/Utils/FileTransferDelegate.h b/Classes/Utils/FileTransferDelegate.h new file mode 100644 index 000000000..a62af10e0 --- /dev/null +++ b/Classes/Utils/FileTransferDelegate.h @@ -0,0 +1,20 @@ +// +// FileTransferDelegate.h +// linphone +// +// Created by Gautier Pelloux-Prayer on 10/06/15. +// +// + +#import + +#import "LinphoneManager.h" + +@interface FileTransferDelegate : NSObject + +- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom; +- (void)cancel; +- (BOOL)download:(LinphoneChatMessage *)message; + +@property() LinphoneChatMessage *message; +@end diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m new file mode 100644 index 000000000..6a6adf1ef --- /dev/null +++ b/Classes/Utils/FileTransferDelegate.m @@ -0,0 +1,207 @@ +// +// FileTransferDelegate.m +// linphone +// +// Created by Gautier Pelloux-Prayer on 10/06/15. +// +// + +#import "FileTransferDelegate.h" +@interface FileTransferDelegate () +@property(strong) NSMutableData *data; +@end + +@implementation FileTransferDelegate + +- (void)dealloc { + if (_message != nil) { + [self cancel]; + } +} + +static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, const LinphoneContent *content, + const LinphoneBuffer *buffer) { + FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message); + size_t size = linphone_buffer_get_size(buffer); + + if (!thiz.data) { + thiz.data = [[NSMutableData alloc] initWithCapacity:linphone_content_get_size(content)]; + } + + if (size == 0) { + LOGI(@"Transfer of %s (%d bytes): download finished", linphone_content_get_name(content), size); + assert([thiz.data length] == linphone_content_get_size(content)); + + // we're finished, save the image and update the message + UIImage *image = [UIImage imageWithData:thiz.data]; + + + [[[LinphoneManager instance] fileTransferDelegates] removeObject:thiz]; + + [[LinphoneManager instance] + .photoLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:(ALAssetOrientation)[image imageOrientation] + completionBlock:^(NSURL *assetURL, NSError *error) { + if (error) { + LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + + UIAlertView *errorAlert = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Transfer error", nil) + message:NSLocalizedString(@"Cannot write image to photo library", nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Ok", nil) + otherButtonTitles:nil, nil]; + [errorAlert show]; + } else { + LOGI(@"Image saved to [%@]", [assetURL absoluteString]); + [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] + forKey:@"localimage" + inMessage:message]; + } + thiz.message = NULL; + [[NSNotificationCenter defaultCenter] + postNotificationName:kLinphoneFileTransferRecvUpdate + object:thiz + userInfo:@{ + @"state" : @(linphone_chat_message_get_state(message)), + @"image" : image, + @"progress" : + @([thiz.data length] * 1.f / linphone_content_get_size(content)), + }]; + + CFRelease((__bridge CFTypeRef)thiz); + }]; + } else { + LOGI(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content), + linphone_content_get_size(content), [thiz.data length], size); + [thiz.data appendBytes:linphone_buffer_get_string_content(buffer) length:size]; + [[NSNotificationCenter defaultCenter] + postNotificationName:kLinphoneFileTransferRecvUpdate + object:thiz + userInfo:@{ + @"state" : @(linphone_chat_message_get_state(message)), + @"progress" : @([thiz.data length] * 1.f / linphone_content_get_size(content)), + }]; + } +} + +static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent *content, + size_t offset, size_t size) { + FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message); + size_t total = thiz.data.length; + if (thiz.data) { + size_t remaining = total - offset; + + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{ + @"state" : @(linphone_chat_message_get_state(message)), + @"progress" : @(offset * 1.f / total), + }]; + LOGI(@"Transfer of %s (%d bytes): already sent %ld, remaining %ld", linphone_content_get_name(content), total, + offset, remaining); + [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneFileTransferSendUpdate + object:thiz + userInfo:dict]; + @try { + return linphone_buffer_new_from_data([thiz.data subdataWithRange:NSMakeRange(offset, size)].bytes, size); + } @catch (NSException *exception) { + LOGE(@"Exception: %@", exception); + } + } else { + LOGE(@"Transfer of %s (%d bytes): %d Error - no upload data in progress!", linphone_content_get_name(content), + total, offset); + } + + return NULL; +} + +static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) { + FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(msg); + + NSString *notification = + linphone_chat_message_is_outgoing(msg) ? kLinphoneFileTransferSendUpdate : kLinphoneFileTransferRecvUpdate; + + const char *text = (linphone_chat_message_get_file_transfer_information(msg) != NULL) + ? "photo transfer" + : linphone_chat_message_get_text(msg); + LOGI(@"Delivery status for [%s] is [%s]", text, linphone_chat_message_state_to_string(state)); + + NSDictionary *dict = @{ @"state" : @(state), @"progress" : @0.f }; + if (state == LinphoneChatMessageStateFileTransferDone || state == LinphoneChatMessageStateFileTransferError) { + thiz.message = NULL; + } + [[NSNotificationCenter defaultCenter] postNotificationName:notification object:thiz userInfo:dict]; + if (linphone_chat_message_is_outgoing(msg)) { + [thiz stopAndDestroy]; + } +} + +- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom { + LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom)); + _data = [NSMutableData dataWithData:UIImageJPEGRepresentation(image, 1.0)]; + linphone_content_set_type(content, "image"); + linphone_content_set_subtype(content, "jpeg"); + linphone_content_set_name(content, + [[NSString stringWithFormat:@"%li-%f.jpg", (long)[image hash], + [NSDate timeIntervalSinceReferenceDate]] UTF8String]); + linphone_content_set_size(content, [_data length]); + + CFTypeRef myself = (__bridge CFTypeRef)self; + _message = linphone_chat_room_create_file_transfer_message(chatRoom, content); + linphone_chat_message_ref(_message); + linphone_chat_message_set_user_data(_message, (void *)CFRetain(myself)); + linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message), + linphone_iphone_file_transfer_send); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status); + + if (url) { + // internal url is saved in the appdata for display and later save + [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:_message]; + } + + linphone_chat_room_send_chat_message(chatRoom, _message); +} + +- (BOOL)download:(LinphoneChatMessage *)message { + _message = message; + // we need to keep a ref on the message to continue downloading even if user quit a chatroom which destroy all chat + // messages + linphone_chat_message_ref(_message); + const char *url = linphone_chat_message_get_external_body_url(_message); + LOGI(@"Content to download: %s", url); + + if (url == nil) + return FALSE; + + linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self)); + + linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message), + linphone_iphone_file_transfer_recv); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status); + + linphone_chat_message_download_file(_message); + + return TRUE; +} + +- (void)stopAndDestroy { + [[[LinphoneManager instance] fileTransferDelegates] removeObject:self]; + if (_message != NULL) { + linphone_chat_message_set_user_data(_message, NULL); + + linphone_chat_message_cbs_set_file_transfer_progress_indication(linphone_chat_message_get_callbacks(_message), + NULL); + linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message), NULL); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), NULL); + linphone_chat_message_cancel_file_transfer(_message); + linphone_chat_message_unref(_message); + } + _message = nil; + _data = nil; +} + +- (void)cancel { + [self stopAndDestroy]; +} + +@end diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index c9d56d7d1..971a7da71 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -29,7 +29,10 @@ OrtpLogLevel ortp_severity; int filesize = 20; if (severity <= LinphoneLoggerDebug) { - ortp_severity = ORTP_DEBUG; + // lol: ortp_debug(XXX) can be disabled at compile time, but ortp_log(ORTP_DEBUG, xxx) will always be valid even + // not in debug build... + ortp_debug("%*s:%3d - %s", filesize, file+MAX((int)strlen(file)-filesize,0), line, [str UTF8String]); + return; } else if(severity <= LinphoneLoggerLog) { ortp_severity = ORTP_MESSAGE; } else if(severity <= LinphoneLoggerWarning) { diff --git a/KifTests/ChatTester.m b/KifTests/ChatTester.m index 1b0056fc5..3c61400e9 100644 --- a/KifTests/ChatTester.m +++ b/KifTests/ChatTester.m @@ -8,6 +8,7 @@ #import "ChatTester.h" #include "LinphoneManager.h" +#import "UIChatRoomCell.h" @implementation ChatTester @@ -17,12 +18,36 @@ - (void)beforeAll { [super beforeAll]; [self switchToValidAccountIfNeeded]; - - [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Chat")]; +} + +- (void)beforeEach { + [super beforeEach]; + if ([tester tryFindingTappableViewWithAccessibilityLabel:LOCALIZED(@"Back") error:nil]) { + [self goBackFromChat]; + } + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Chat")]; + [self removeAllRooms]; +} + +- (void)afterAll { + // at the end of tests, go back to chat rooms to display main bar + if ([tester tryFindingTappableViewWithAccessibilityLabel:LOCALIZED(@"Back") error:nil]) { + [self goBackFromChat]; + } } #pragma mark - tools +- (void)removeAllRooms { + [tester tapViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton]; + while ( + [tester tryFindingTappableViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton error:nil]) { + [tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton]; + } + [tester tapViewWithAccessibilityLabel:@"Edit" + traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen +} + - (void)goBackFromChat { [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Back")]; } @@ -114,29 +139,91 @@ for( int i =0; i< uuids.count; i++){ [tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton]; } - - // then we try to delete all the rest of chatrooms - while ( [tester tryFindingTappableViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton error:nil] ) - { - [tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton]; - NSLog(@"Deleting an extra chat"); - } - - [tester tapViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen - - // check that the tableview is empty - UITableView* tv = nil; - NSError* err = nil; - if( [tester tryFindingAccessibilityElement:nil view:&tv withIdentifier:@"ChatRoom list" tappable:false error:&err] ){ - XCTAssert(tv != nil); - XCTAssert([tv numberOfRowsInSection:0] == 0); // no more chat rooms - } else { - NSLog(@"Error: %@",err); - } - - // test that there's no more chatrooms in the core - XCTAssert(linphone_core_get_chat_rooms([LinphoneManager getLc]) == nil); + + [tester tapViewWithAccessibilityLabel:@"Edit" + traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen + + // check that the tableview is empty + UITableView *tv = [self findTableView:@"ChatRoom list"]; + XCTAssert([tv numberOfRowsInSection:0] == 0); + + // test that there's no more chatrooms in the core + XCTAssert(linphone_core_get_chat_rooms([LinphoneManager getLc]) == nil); } +- (UITableView *)findTableView:(NSString *)table { + UITableView *tv = nil; + NSError *err = nil; + if ([tester tryFindingAccessibilityElement:nil view:&tv withIdentifier:table tappable:false error:&err]) { + XCTAssertNotNil(tv); + } else { + XCTFail(@"Error: %@", err); + } + return tv; +} + +- (void)uploadImage { + NSString *user = @"testios"; + + [self startChatWith:user]; + + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Send picture")]; + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Photo library")]; + // if popup "Linphone would access your photo" pops up, click OK. + if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusNotDetermined) { + [tester acknowledgeSystemAlert]; + } + + [tester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:1]; + + // TODO: do not harcode size! + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Minimum (108.9 KB)")]; + + UITableView *tv = [self findTableView:@"Chat list"]; + XCTAssertEqual([tv numberOfRowsInSection:0], 1); + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 1); +} + +- (void)testUploadImage { + NSString *user = @"testios"; + + [self uploadImage]; + [self goBackFromChat]; + + // if we go back to the same chatroom, the message should be still there + [self startChatWith:user]; + UITableView *tv = [self findTableView:@"Chat list"]; + XCTAssertEqual([tv numberOfRowsInSection:0], 1); + + [tester waitForViewWithAccessibilityLabel:LOCALIZED(@"Download")]; + + XCTAssertEqual([tv numberOfRowsInSection:0], 2); + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)testCancelUploadImage { + [self uploadImage]; + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Cancel transfer")]; + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)downloadImage { + [self uploadImage]; + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Download")]; + [tester waitForTimeInterval:.5f]; // just wait a few secs to start download + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 1); +} + +- (void)testDownloadImage { + [self downloadImage]; + [tester waitForAbsenceOfViewWithAccessibilityLabel:@"Cancel transfer"]; + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} + +- (void)testCancelDownloadImage { + [self downloadImage]; + [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Cancel transfer")]; + XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0); +} @end diff --git a/Resources/linphonerc b/Resources/linphonerc index 0f3e852c7..b773a7c27 100644 --- a/Resources/linphonerc +++ b/Resources/linphonerc @@ -73,7 +73,7 @@ username_length=4 expires=1314000 push_notification=1 transport=tls -sharing_server=https://www.linphone.org:444/upload.php +sharing_server=https://www.linphone.org:444/lft.php ice=1 stun=stun.linphone.org diff --git a/Resources/linphonerc~ipad b/Resources/linphonerc~ipad index 787349e1a..d2e96d5c1 100644 --- a/Resources/linphonerc~ipad +++ b/Resources/linphonerc~ipad @@ -73,7 +73,7 @@ username_length=4 expires=1314000 push_notification=1 transport=tls -sharing_server=https://www.linphone.org:444/upload.php +sharing_server=https://www.linphone.org:444/lft.php ice=1 stun=stun.linphone.org diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 7cf06a6bf..c31fe3c6b 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -120,6 +120,7 @@ 636316D41A1DEC650009B839 /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D61A1DEC650009B839 /* SettingsViewController.xib */; }; 636316D91A1DECC90009B839 /* PhoneMainView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D71A1DECC90009B839 /* PhoneMainView.xib */; }; 636316DE1A1DEF2F0009B839 /* UIButtonShrinkable.m in Sources */ = {isa = PBXBuildFile; fileRef = 636316DD1A1DEF2F0009B839 /* UIButtonShrinkable.m */; }; + 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 637157A01B283FE200C91677 /* FileTransferDelegate.m */; }; 639CEAFD1A1DF4D9004DE38F /* UIStateBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEAFF1A1DF4D9004DE38F /* UIStateBar.xib */; }; 639CEB001A1DF4E4004DE38F /* UIHistoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB021A1DF4E4004DE38F /* UIHistoryCell.xib */; }; 639CEB031A1DF4EB004DE38F /* UICompositeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB051A1DF4EB004DE38F /* UICompositeViewController.xib */; }; @@ -306,7 +307,6 @@ D36C43F7158F61EA0048BA40 /* call_state_play_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D36C43F0158F61EA0048BA40 /* call_state_play_over.png */; }; D36FB2D51589EF7C0036F6F2 /* UIPauseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */; }; D37295DB158B3C9600D2C0C7 /* video_off_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D37295DA158B3C9600D2C0C7 /* video_off_disabled.png */; }; - D374D3FD16071762003D25FF /* ImageSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = D374D3FC16071762003D25FF /* ImageSharing.m */; }; D377BBFA15A19DA6002B696B /* video_on_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D377BBF915A19DA6002B696B /* video_on_disabled.png */; }; D378906515AC373B00BD776C /* ContactDetailsLabelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D378906315AC373B00BD776C /* ContactDetailsLabelViewController.m */; }; D378AB2A15DCDB4A0098505D /* ImagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D378AB2915DCDB490098505D /* ImagePickerViewController.m */; }; @@ -892,7 +892,6 @@ /* Begin PBXFileReference section */ 045B5CB218D72E9A0088350C /* libbzrtp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbzrtp.a; path = "liblinphone-sdk/apple-darwin/lib/libbzrtp.a"; sourceTree = ""; }; - 15017E6F1773578400784ACB /* libxml2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libxml2.a; path = "liblinphone-sdk/apple-darwin/lib/libxml2.a"; sourceTree = ""; }; 152F22331B15E83B008C0621 /* libilbcrfc3951.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbcrfc3951.a; path = "liblinphone-sdk/apple-darwin/lib/libilbcrfc3951.a"; sourceTree = ""; }; 152F22351B15E889008C0621 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; 1560821E18EEF26100765332 /* libmsopenh264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsopenh264.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsopenh264.a"; sourceTree = ""; }; @@ -1039,6 +1038,8 @@ 636316DB1A1DEDD80009B839 /* ru */ = {isa = PBXFileReference; fileEncoding = 2483028224; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HistoryDetailsViewController.strings; sourceTree = ""; }; 636316DC1A1DEECB0009B839 /* UIButtonShrinkable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIButtonShrinkable.h; sourceTree = ""; }; 636316DD1A1DEF2F0009B839 /* UIButtonShrinkable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIButtonShrinkable.m; sourceTree = ""; }; + 6371579F1B283FE200C91677 /* FileTransferDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTransferDelegate.h; path = Utils/FileTransferDelegate.h; sourceTree = ""; }; + 637157A01B283FE200C91677 /* FileTransferDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTransferDelegate.m; path = Utils/FileTransferDelegate.m; sourceTree = ""; }; 639CEAFE1A1DF4D9004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIStateBar.xib; sourceTree = ""; }; 639CEB011A1DF4E4004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIHistoryCell.xib; sourceTree = ""; }; 639CEB041A1DF4EB004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UICompositeViewController.xib; sourceTree = ""; }; @@ -1258,8 +1259,6 @@ D36FB2D31589EF7C0036F6F2 /* UIPauseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIPauseButton.h; sourceTree = ""; }; D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIPauseButton.m; sourceTree = ""; }; D37295DA158B3C9600D2C0C7 /* video_off_disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = video_off_disabled.png; path = Resources/video_off_disabled.png; sourceTree = ""; }; - D374D3FB16071762003D25FF /* ImageSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageSharing.h; sourceTree = ""; }; - D374D3FC16071762003D25FF /* ImageSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageSharing.m; sourceTree = ""; }; D377BBF915A19DA6002B696B /* video_on_disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = video_on_disabled.png; path = Resources/video_on_disabled.png; sourceTree = ""; }; D378906215AC373B00BD776C /* ContactDetailsLabelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsLabelViewController.h; sourceTree = ""; }; D378906315AC373B00BD776C /* ContactDetailsLabelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactDetailsLabelViewController.m; sourceTree = ""; }; @@ -2041,8 +2040,6 @@ D38187D415FE346B00C3EDCA /* HistoryViewController.xib */, D378AB2815DCDB480098505D /* ImagePickerViewController.h */, D378AB2915DCDB490098505D /* ImagePickerViewController.m */, - D374D3FB16071762003D25FF /* ImageSharing.h */, - D374D3FC16071762003D25FF /* ImageSharing.m */, 22405EFD1601C19000B92522 /* ImageViewController.h */, 22405EFE1601C19100B92522 /* ImageViewController.m */, D37EE11016035793003608A6 /* ImageViewController.xib */, @@ -2319,7 +2316,6 @@ D30BF33216A427BC00AF0026 /* libtunnel.a */, 7066FC0B13E830E400EFC6DC /* libvpx.a */, 22AA8AFB13D7125500B30535 /* libx264.a */, - 15017E6F1773578400784ACB /* libxml2.a */, F0B89C2118DC89E30050B60E /* MediaPlayer.framework */, D37DC7171594AF3400B2A5EB /* MessageUI.framework */, 226EF06B15FA256B005865C7 /* MobileCoreServices.framework */, @@ -2345,6 +2341,8 @@ D37EE15F160377D7003608A6 /* DTFoundation */, D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */, D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */, + 6371579F1B283FE200C91677 /* FileTransferDelegate.h */, + 637157A01B283FE200C91677 /* FileTransferDelegate.m */, D3ED40141602172200BF332B /* GrowingTextView */, D3807FC715C2894A005BE9BC /* InAppSettingsKit */, D3B90E1115C2CB5700F64F8C /* NinePatch.xcodeproj */, @@ -4059,13 +4057,13 @@ D380800515C28A7A005BE9BC /* UILinphone.m in Sources */, D380801315C299D0005BE9BC /* ColorSpaceUtilites.m in Sources */, 6359DE7F1ADEB54200EA15C0 /* InAppProductsViewController.m in Sources */, + 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */, D378AB2A15DCDB4A0098505D /* ImagePickerViewController.m in Sources */, 6359DE841ADEB64100EA15C0 /* InAppProductsCell.m in Sources */, 22405F001601C19200B92522 /* ImageViewController.m in Sources */, D3ED40191602172200BF332B /* HPGrowingTextView.m in Sources */, D3ED401B1602172200BF332B /* HPTextViewInternal.m in Sources */, D37EE162160377D7003608A6 /* DTActionSheet.m in Sources */, - D374D3FD16071762003D25FF /* ImageSharing.m in Sources */, D35E91F4160CA10B0023116B /* UILinphoneTextField.m in Sources */, D35E91F8160CA4FF0023116B /* UILinphoneButton.m in Sources */, D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */, diff --git a/submodules/belle-sip b/submodules/belle-sip index 611762072..778fbca58 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 611762072933bf7bcbac9848bfead5a367a22ded +Subproject commit 778fbca580812d759979c8431b01899feafa93cd diff --git a/submodules/linphone b/submodules/linphone index ad1d7c12c..869938486 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit ad1d7c12c9b459660b34d63408b144bf5890f3b6 +Subproject commit 869938486e66225ded9d46d534a24df30a84d953 diff --git a/submodules/msopenh264 b/submodules/msopenh264 index 172e97a83..40c29ef77 160000 --- a/submodules/msopenh264 +++ b/submodules/msopenh264 @@ -1 +1 @@ -Subproject commit 172e97a83aa2a868fd3dbbd6e7d57ad7d55f3054 +Subproject commit 40c29ef7736feb11af1e34f587788e49fa18b5c8 From 40c3d74c6b473a03ea8c2a7931ad96b19eb2422e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 15 Jun 2015 15:57:22 +0200 Subject: [PATCH 23/36] ChatTester.m: acknowledgeSystemAlert only available on simulator --- KifTests/ChatTester.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/KifTests/ChatTester.m b/KifTests/ChatTester.m index 3c61400e9..2b890443a 100644 --- a/KifTests/ChatTester.m +++ b/KifTests/ChatTester.m @@ -171,7 +171,9 @@ [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Photo library")]; // if popup "Linphone would access your photo" pops up, click OK. if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusNotDetermined) { +#if TARGET_IPHONE_SIMULATOR [tester acknowledgeSystemAlert]; +#endif } [tester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:1]; From 9a0f9a649d6b37b874fe2fa0ba4dee9642c298bc Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 15 Jun 2015 16:32:48 +0200 Subject: [PATCH 24/36] FileTransfer: remove some debug code and fix camera upload too --- Classes/ChatRoomViewController.m | 26 +++++++++++- Classes/LinphoneUI/UIChatRoomCell.m | 65 +++++++++++++++++++---------- 2 files changed, 69 insertions(+), 22 deletions(-) diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 5509d9efa..fbcbc6ac9 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -291,7 +291,31 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (void)saveAndSend:(UIImage*)image url:(NSURL*)url { - [self chatRoomStartImageUpload:image url:url]; + // photo from Camera, must be saved first + if (url == nil) { + [[LinphoneManager instance] + .photoLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:(ALAssetOrientation)[image imageOrientation] + completionBlock:^(NSURL *assetURL, NSError *error) { + if (error) { + LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + + UIAlertView *errorAlert = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Transfer error", nil) + message:NSLocalizedString(@"Cannot write image to photo library", nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Ok", nil) + otherButtonTitles:nil, nil]; + [errorAlert show]; + } else { + LOGI(@"Image saved to [%@]", [assetURL absoluteString]); + [self chatRoomStartImageUpload:image url:assetURL]; + } + }]; + } else { + [self chatRoomStartImageUpload:image url:url]; + } } - (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url { diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index 34a341a96..21d11c0c1 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -67,6 +67,7 @@ static UIFont *CELL_FONT = nil; resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)]; [dateLabel addGestureRecognizer:resendTapGestureRecognizer]; + [statusImage addGestureRecognizer:resendTapGestureRecognizer]; [self addSubview:innerView]; [deleteButton setAlpha:0.0f]; @@ -368,17 +369,21 @@ static UIFont *CELL_FONT = nil; - (IBAction)onImageClick:(id)event { - // if(![messageImageView isLoading]) { - // ImageViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] - // changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], ImageViewController); - // if(controller != nil) { - // CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; - // UIImage* fullScreen = [UIImage imageWithCGImage:fullScreenRef]; - // [controller setImage:fullScreen]; - // } - // } - - [LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:chat]; + LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat); + if (state == LinphoneChatMessageStateNotDelivered) { + [self onResendClick:nil]; + } else { + if (![messageImageView isLoading]) { + ImageViewController *controller = DYNAMIC_CAST( + [[PhoneMainView instance] changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], + ImageViewController); + if (controller != nil) { + CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; + UIImage *fullScreen = [UIImage imageWithCGImage:fullScreenRef]; + [controller setImage:fullScreen]; + } + } + } } - (IBAction)onResendClick:(id)event { @@ -386,18 +391,36 @@ static UIFont *CELL_FONT = nil; LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat); if (state == LinphoneChatMessageStateNotDelivered) { - const char* text = linphone_chat_message_get_text(self->chat); - const char* url = linphone_chat_message_get_external_body_url(self->chat); - NSString* message = text ? [NSString stringWithUTF8String:text] : nil; - NSString* exturl = url ? [NSString stringWithUTF8String:url] : nil; + if (linphone_chat_message_get_file_transfer_information(chat) != NULL) { + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat]; + NSURL *imageUrl = [NSURL URLWithString:localImage]; - [self onDeleteClick:nil]; + [self onDeleteClick:nil]; - double delayInSeconds = 0.4; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - [chatRoomDelegate resendChat:message withExternalUrl:exturl]; - }); + [[LinphoneManager instance] + .photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]]; + [chatRoomDelegate chatRoomStartImageUpload:image url:imageUrl]; + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } else { + const char *text = linphone_chat_message_get_text(self->chat); + NSString *message = text ? [NSString stringWithUTF8String:text] : nil; + + [self onDeleteClick:nil]; + + double delayInSeconds = 0.4; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { + [chatRoomDelegate resendChat:message withExternalUrl:nil]; + }); + } } } From 28140195bb6ecac825ba09c7cb4290bb7d9643eb Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 15 Jun 2015 17:45:05 +0200 Subject: [PATCH 25/36] InApp: remove unused classes --- Classes/InAppProductsCell.h | 27 -------- Classes/InAppProductsCell.m | 60 ---------------- Classes/InAppProductsCell.xib | 58 ---------------- Classes/InAppProductsManager.m | 1 - Classes/InAppProductsTableViewController.h | 13 ---- Classes/InAppProductsTableViewController.m | 78 --------------------- Classes/InAppProductsViewController.h | 20 ------ Classes/InAppProductsViewController.m | 80 ---------------------- Classes/InAppProductsViewController.xib | 70 ------------------- Classes/PhoneMainView.m | 1 - Classes/SettingsViewController.m | 3 - Settings/InAppSettings.bundle/Root.plist | 8 --- linphone.xcodeproj/project.pbxproj | 26 ------- 13 files changed, 445 deletions(-) delete mode 100644 Classes/InAppProductsCell.h delete mode 100644 Classes/InAppProductsCell.m delete mode 100644 Classes/InAppProductsCell.xib delete mode 100644 Classes/InAppProductsTableViewController.h delete mode 100644 Classes/InAppProductsTableViewController.m delete mode 100644 Classes/InAppProductsViewController.h delete mode 100644 Classes/InAppProductsViewController.m delete mode 100644 Classes/InAppProductsViewController.xib diff --git a/Classes/InAppProductsCell.h b/Classes/InAppProductsCell.h deleted file mode 100644 index 4efa640ee..000000000 --- a/Classes/InAppProductsCell.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// InAppProductsCell.h -// linphone -// -// Created by Gautier Pelloux-Prayer on 15/04/15. -// -// - -#import -#import - -@interface InAppProductsCell : UITableViewCell { -} -@property (strong, nonatomic) IBOutlet UILabel *ptitle; -@property (strong, nonatomic) IBOutlet UILabel *pdescription; -@property (strong, nonatomic) IBOutlet UILabel *pprice; -@property (strong, nonatomic) IBOutlet UISwitch *ppurchased; -@property (nonatomic) BOOL isMaximized; -@property (strong, nonatomic) NSString *productID; - -- (id)initWithIdentifier:(NSString*)identifier maximized:(bool)maximized; - -+ (CGFloat)getHeight:(BOOL)maximized; - -- (void)fillFromProduct:(SKProduct*)prod; - -@end diff --git a/Classes/InAppProductsCell.m b/Classes/InAppProductsCell.m deleted file mode 100644 index e0e8ea763..000000000 --- a/Classes/InAppProductsCell.m +++ /dev/null @@ -1,60 +0,0 @@ -// -// InAppProductsCell.m -// linphone -// -// Created by Gautier Pelloux-Prayer on 15/04/15. -// -// - -#import "InAppProductsCell.h" -#import "LinphoneManager.h" - -@implementation InAppProductsCell - -- (void)setIsMaximized:(BOOL)isMaximized { - _isMaximized = isMaximized; - - //show the BUY button only when not maximized -// _buyButton.hidden = !isMaximized; - - self.frame = CGRectMake(self.frame.origin.x, - self.frame.origin.y, - self.frame.size.width, - [InAppProductsCell getHeight:isMaximized]); -} - -- (void)fillFromProduct:(SKProduct *)prod { - NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; - [formatter setLocale:prod.priceLocale]; - [formatter setNumberStyle:NSNumberFormatterCurrencyStyle]; - NSString * formattedPrice = [formatter stringFromNumber:prod.price]; - - [_ptitle setText: [prod localizedTitle]]; - [_pdescription setText: [prod localizedDescription]]; - [_pprice setText: formattedPrice]; - [_ppurchased setOn: [[[LinphoneManager instance] iapManager] isPurchasedWithID:prod.productIdentifier]]; - _productID = prod.productIdentifier; -} -- (id)initWithIdentifier:(NSString*)identifier maximized:(bool)maximized { - if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) { - NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"InAppProductsCell" - owner:self - options:nil]; - if ([arrayOfViews count] >= 1) { - [self.contentView addSubview:[arrayOfViews objectAtIndex:0]]; - } - _isMaximized = maximized; - } - return self; -} - - -- (NSString *)description { - return [NSString stringWithFormat:@"%@ (%@): %@ (%@)", _ptitle.text, _pprice.text, _pdescription.text, _isMaximized ? @"maximized":@"minimized"]; -} - -+ (CGFloat)getHeight:(BOOL)maximized { - return maximized ? 40 : 40; -} - -@end diff --git a/Classes/InAppProductsCell.xib b/Classes/InAppProductsCell.xib deleted file mode 100644 index 73791c7a4..000000000 --- a/Classes/InAppProductsCell.xib +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Classes/InAppProductsManager.m b/Classes/InAppProductsManager.m index 847697868..f4e77fac9 100644 --- a/Classes/InAppProductsManager.m +++ b/Classes/InAppProductsManager.m @@ -29,7 +29,6 @@ #import "LinphoneManager.h" #import "PhoneMainView.h" -#import "InAppProductsViewController.h" @interface InAppProductsManager() @property (strong, nonatomic) NSDate *expirationDate; diff --git a/Classes/InAppProductsTableViewController.h b/Classes/InAppProductsTableViewController.h deleted file mode 100644 index a98352c37..000000000 --- a/Classes/InAppProductsTableViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// InAppProductsTableViewController.h -// linphone -// -// Created by Gautier Pelloux-Prayer on 16/04/15. -// -// - -#import - -@interface InAppProductsTableViewController : UITableViewController - -@end diff --git a/Classes/InAppProductsTableViewController.m b/Classes/InAppProductsTableViewController.m deleted file mode 100644 index 6c5232283..000000000 --- a/Classes/InAppProductsTableViewController.m +++ /dev/null @@ -1,78 +0,0 @@ -// -// InAppProductsTableViewController.m -// linphone -// -// Created by Gautier Pelloux-Prayer on 16/04/15. -// -// - -#import "InAppProductsTableViewController.h" -#import "InAppProductsCell.h" -#import "InAppProductsManager.h" -#import "LinphoneManager.h" -#import "DTAlertView.h" - -@implementation InAppProductsTableViewController { - NSInteger currentExpanded; - InAppProductsManager *iapm; -} - -- (void)viewWillAppear:(BOOL)animated { - currentExpanded = -1; - iapm = [[LinphoneManager instance] iapManager]; -} - -#pragma mark - Table view data source - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 1; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return [iapm productsAvailable].count; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *kCellId = @"InAppProductsCell"; - InAppProductsCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId]; - if (cell == nil) { - cell = [[InAppProductsCell alloc] initWithIdentifier:kCellId maximized:(currentExpanded == indexPath.row)]; - } - SKProduct *prod = [[[[LinphoneManager instance] iapManager] productsAvailable] objectAtIndex:indexPath.row]; - [cell fillFromProduct:prod]; - cell.isMaximized = (currentExpanded == indexPath.row); - return cell; -} - -//- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { -// if(currentExpanded == indexPath.row) { -// currentExpanded = -1; -// [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; -// return; -// } else if(currentExpanded >= 0) { -// NSIndexPath *previousPath = [NSIndexPath indexPathForRow:currentExpanded inSection:0]; -// currentExpanded = indexPath.row; -// [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade]; -// } -// currentExpanded = indexPath.row; -// [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; -//} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - InAppProductsCell *cell = (InAppProductsCell*)[tableView cellForRowAtIndexPath:indexPath]; - if (cell.ppurchased.isOn) { - DTAlertView* alert = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Already purchased", nil) message: [NSString stringWithFormat:NSLocalizedString(@"You already bought %@.",nil), cell.ptitle.text]]; - - [alert addCancelButtonWithTitle:NSLocalizedString(@"OK", nil) block:nil]; - [alert show]; - } else { - //try to purchase item, and if successfull change the switch - [[[LinphoneManager instance] iapManager] purchaseWitID: cell.productID]; - } -} - --(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - return [InAppProductsCell getHeight:(currentExpanded == indexPath.row)]; -} - -@end diff --git a/Classes/InAppProductsViewController.h b/Classes/InAppProductsViewController.h deleted file mode 100644 index 84ad3469d..000000000 --- a/Classes/InAppProductsViewController.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// InAppProductsViewController.h -// linphone -// -// Created by Gautier Pelloux-Prayer on 15/04/15. -// -// - -#import -#import "UICompositeViewController.h" -#import "InAppProductsTableViewController.h" - -@interface InAppProductsViewController : UIViewController { -} - -@property (nonatomic, strong) IBOutlet InAppProductsTableViewController* tableController; -@property (strong, nonatomic) IBOutlet UIView *waitView; -- (IBAction)onRestoreClicked:(UIButton *)sender; - -@end diff --git a/Classes/InAppProductsViewController.m b/Classes/InAppProductsViewController.m deleted file mode 100644 index 2154a82b0..000000000 --- a/Classes/InAppProductsViewController.m +++ /dev/null @@ -1,80 +0,0 @@ -// -// InAppProductsViewController.m -// linphone -// -// Created by Gautier Pelloux-Prayer on 15/04/15. -// -// - -#import "InAppProductsViewController.h" -#import "InAppProductsCell.h" - -@implementation InAppProductsViewController - -#pragma mark - Lifecycle Functions - -- (id)init { - return [super initWithNibName:@"InAppProductsViewController" bundle:[NSBundle mainBundle]]; -} - - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - -} - -#pragma mark - ViewController Functions - -- (void)viewDidLoad { - [super viewDidLoad]; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - for (NSString* notification in [NSArray arrayWithObjects:kIAPReady, kIAPRestoreSucceeded, kIAPPurchaseSucceeded, kIAPReceiptSucceeded, kIAPPurchaseTrying, nil]) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(onIAPPurchaseNotification:) - name:notification - object:nil]; - } -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - for (NSString* notification in [NSArray arrayWithObjects:kIAPReady, kIAPRestoreSucceeded, kIAPPurchaseSucceeded, kIAPReceiptSucceeded, kIAPPurchaseTrying, nil]) { - [[NSNotificationCenter defaultCenter] removeObserver:self - name:notification - object:nil]; - } -} - -- (void)onIAPPurchaseNotification:(NSNotification*)notif { - InAppProductsManager *iapm = [[LinphoneManager instance] iapManager]; - [[_tableController tableView] reloadData]; - [_waitView setHidden:([[iapm productsAvailable] count] != 0 && ![notif.name isEqualToString:kIAPPurchaseTrying])]; -} - -#pragma mark - UICompositeViewDelegate Functions - -static UICompositeViewDescription *compositeDescription = nil; - -+ (UICompositeViewDescription *)compositeViewDescription { - if(compositeDescription == nil) { - compositeDescription = [[UICompositeViewDescription alloc] init:@"InAppProducts" - content:@"InAppProductsViewController" - stateBar:nil - stateBarEnabled:false - tabBar: @"UIMainBar" - tabBarEnabled:true - fullscreen:false - landscapeMode:[LinphoneManager runningOnIpad] - portraitMode:true]; - } - return compositeDescription; -} - -- (IBAction)onRestoreClicked:(UIButton *)sender { - [[[LinphoneManager instance] iapManager] restore]; -} -@end \ No newline at end of file diff --git a/Classes/InAppProductsViewController.xib b/Classes/InAppProductsViewController.xib deleted file mode 100644 index 4864c1eb0..000000000 --- a/Classes/InAppProductsViewController.xib +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index d5a9eeec8..2298bd5f1 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -20,7 +20,6 @@ #import #import -#import "InAppProductsViewController.h" #import "LinphoneAppDelegate.h" #import "PhoneMainView.h" #import "Utils.h" diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index d1a07dec2..9fab910a9 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -22,7 +22,6 @@ #import "PhoneMainView.h" #import "UILinphone.h" #import "UACellBackgroundView.h" -#import "InAppProductsViewController.h" #import "DCRoundSwitch.h" @@ -770,8 +769,6 @@ static UICompositeViewDescription *compositeDescription = nil; } [self emailAttachment:[NSData dataWithContentsOfFile:[NSString stringWithUTF8String:filepath]] mimeType:mimeType name:filename]; ms_free(filepath); - } else if([key isEqual:@"in_app_products_button"]) { - [[PhoneMainView instance] changeCurrentView:[InAppProductsViewController compositeViewDescription] push:TRUE]; } } diff --git a/Settings/InAppSettings.bundle/Root.plist b/Settings/InAppSettings.bundle/Root.plist index a3ad75a6c..90c75b377 100644 --- a/Settings/InAppSettings.bundle/Root.plist +++ b/Settings/InAppSettings.bundle/Root.plist @@ -242,14 +242,6 @@ Type PSChildPaneSpecifier - - Key - in_app_products_button - Title - Extra features - Type - IASKButtonSpecifier - Title Development debug actions diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index c31fe3c6b..b96c6ad3b 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -111,11 +111,6 @@ 630CF5571AF7CE1500539F7A /* UITextField+DoneButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 630CF5561AF7CE1500539F7A /* UITextField+DoneButton.m */; }; 631C4FB119D2A8F2004BFE77 /* UIDigitButtonLongPlus.m in Sources */ = {isa = PBXBuildFile; fileRef = 631C4FB019D2A8F2004BFE77 /* UIDigitButtonLongPlus.m */; }; 631C4FB719D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 631C4FB619D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.m */; }; - 6359DE7F1ADEB54200EA15C0 /* InAppProductsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6359DE7D1ADEB54200EA15C0 /* InAppProductsViewController.m */; }; - 6359DE801ADEB54200EA15C0 /* InAppProductsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6359DE7E1ADEB54200EA15C0 /* InAppProductsViewController.xib */; }; - 6359DE841ADEB64100EA15C0 /* InAppProductsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6359DE821ADEB64100EA15C0 /* InAppProductsCell.m */; }; - 6359DE851ADEB64100EA15C0 /* InAppProductsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6359DE831ADEB64100EA15C0 /* InAppProductsCell.xib */; }; - 6359DE8B1ADF9EB900EA15C0 /* InAppProductsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6359DE8A1ADF9EB900EA15C0 /* InAppProductsTableViewController.m */; }; 636316D11A1DEBCB0009B839 /* AboutViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D31A1DEBCB0009B839 /* AboutViewController.xib */; }; 636316D41A1DEC650009B839 /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D61A1DEC650009B839 /* SettingsViewController.xib */; }; 636316D91A1DECC90009B839 /* PhoneMainView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D71A1DECC90009B839 /* PhoneMainView.xib */; }; @@ -1023,14 +1018,6 @@ 631C4FB519D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIDigitButtonLongVoiceMail.h; sourceTree = ""; }; 631C4FB619D2C3A6004BFE77 /* UIDigitButtonLongVoiceMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIDigitButtonLongVoiceMail.m; sourceTree = ""; }; 633E388219FFB0F400936D1C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 6359DE7C1ADEB54200EA15C0 /* InAppProductsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InAppProductsViewController.h; sourceTree = ""; }; - 6359DE7D1ADEB54200EA15C0 /* InAppProductsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InAppProductsViewController.m; sourceTree = ""; }; - 6359DE7E1ADEB54200EA15C0 /* InAppProductsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InAppProductsViewController.xib; sourceTree = ""; }; - 6359DE811ADEB64100EA15C0 /* InAppProductsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InAppProductsCell.h; sourceTree = ""; }; - 6359DE821ADEB64100EA15C0 /* InAppProductsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InAppProductsCell.m; sourceTree = ""; }; - 6359DE831ADEB64100EA15C0 /* InAppProductsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InAppProductsCell.xib; sourceTree = ""; }; - 6359DE891ADF9EB900EA15C0 /* InAppProductsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InAppProductsTableViewController.h; sourceTree = ""; }; - 6359DE8A1ADF9EB900EA15C0 /* InAppProductsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InAppProductsTableViewController.m; sourceTree = ""; }; 636316D21A1DEBCB0009B839 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AboutViewController.xib; sourceTree = ""; }; 636316D51A1DEC650009B839 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SettingsViewController.xib; sourceTree = ""; }; 636316D81A1DECC90009B839 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PhoneMainView.xib; sourceTree = ""; }; @@ -2043,16 +2030,8 @@ 22405EFD1601C19000B92522 /* ImageViewController.h */, 22405EFE1601C19100B92522 /* ImageViewController.m */, D37EE11016035793003608A6 /* ImageViewController.xib */, - 6359DE811ADEB64100EA15C0 /* InAppProductsCell.h */, - 6359DE821ADEB64100EA15C0 /* InAppProductsCell.m */, - 6359DE831ADEB64100EA15C0 /* InAppProductsCell.xib */, 63E59A3D1ADE6ECB00646FB3 /* InAppProductsManager.h */, 63E59A3E1ADE70D900646FB3 /* InAppProductsManager.m */, - 6359DE891ADF9EB900EA15C0 /* InAppProductsTableViewController.h */, - 6359DE8A1ADF9EB900EA15C0 /* InAppProductsTableViewController.m */, - 6359DE7C1ADEB54200EA15C0 /* InAppProductsViewController.h */, - 6359DE7D1ADEB54200EA15C0 /* InAppProductsViewController.m */, - 6359DE7E1ADEB54200EA15C0 /* InAppProductsViewController.xib */, D31AAF5C159B3919002C6B02 /* InCallTableViewController.h */, D31AAF5D159B3919002C6B02 /* InCallTableViewController.m */, D3F83EE91582021700336684 /* InCallViewController.h */, @@ -3342,7 +3321,6 @@ D38327F71580FE3A00FA0D23 /* settings_default.png in Resources */, D38327F81580FE3A00FA0D23 /* settings_selected.png in Resources */, D38327F91580FE3A00FA0D23 /* chat_default.png in Resources */, - 6359DE801ADEB54200EA15C0 /* InAppProductsViewController.xib in Resources */, D38327FA1580FE3A00FA0D23 /* chat_selected.png in Resources */, D3832800158100E400FA0D23 /* contacts_over.png in Resources */, D3832801158100E400FA0D23 /* history_over.png in Resources */, @@ -3379,7 +3357,6 @@ D3F83F581582223B00336684 /* numpad_five_default.png in Resources */, D3F83F5A1582223B00336684 /* numpad_five_over.png in Resources */, D3F83F5C1582223B00336684 /* numpad_six_default.png in Resources */, - 6359DE851ADEB64100EA15C0 /* InAppProductsCell.xib in Resources */, 636316D91A1DECC90009B839 /* PhoneMainView.xib in Resources */, D3F83F5E1582223B00336684 /* numpad_six_over.png in Resources */, D3F83F601582223B00336684 /* numpad_seven_default.png in Resources */, @@ -4052,14 +4029,11 @@ D3807FFC15C2894A005BE9BC /* IASKPSTitleValueSpecifierViewCell.m in Sources */, D3807FFE15C2894A005BE9BC /* IASKSlider.m in Sources */, D380800015C2894A005BE9BC /* IASKSwitch.m in Sources */, - 6359DE8B1ADF9EB900EA15C0 /* InAppProductsTableViewController.m in Sources */, D380800215C2894A005BE9BC /* IASKTextField.m in Sources */, D380800515C28A7A005BE9BC /* UILinphone.m in Sources */, D380801315C299D0005BE9BC /* ColorSpaceUtilites.m in Sources */, - 6359DE7F1ADEB54200EA15C0 /* InAppProductsViewController.m in Sources */, 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */, D378AB2A15DCDB4A0098505D /* ImagePickerViewController.m in Sources */, - 6359DE841ADEB64100EA15C0 /* InAppProductsCell.m in Sources */, 22405F001601C19200B92522 /* ImageViewController.m in Sources */, D3ED40191602172200BF332B /* HPGrowingTextView.m in Sources */, D3ED401B1602172200BF332B /* HPTextViewInternal.m in Sources */, From 3712c624ce40ebb2d4660ae993951006a737f7e6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 16 Jun 2015 11:00:13 +0200 Subject: [PATCH 26/36] submodules: update linphone to get latest ortp CMakeLists.txt for debug logs --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index a312cb898..e7db15457 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit a312cb898815878f2833053c2e0c60d34afc9458 +Subproject commit e7db1545745344aeb7077d8e3d432dcdf2018f8f From a4db6e8793bd59d6d0739271ac86950e13bcf4c6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 16 Jun 2015 11:49:08 +0200 Subject: [PATCH 27/36] prepare.py: display some user-friendly errors when giving invalid commands --- prepare.py | 289 +++++++++++++++++++------------------ submodules/cmake-builder | 2 +- submodules/libilbc-rfc3951 | 2 +- 3 files changed, 154 insertions(+), 139 deletions(-) diff --git a/prepare.py b/prepare.py index f725375ab..ac9fdfc30 100755 --- a/prepare.py +++ b/prepare.py @@ -27,6 +27,7 @@ import os import re import shutil import sys +from subprocess import Popen sys.dont_write_bytecode = True sys.path.insert(0, 'submodules/cmake-builder') import prepare @@ -34,48 +35,48 @@ import prepare class IOSTarget(prepare.Target): - def __init__(self, arch): - prepare.Target.__init__(self, 'ios-' + arch) - current_path = os.path.dirname(os.path.realpath(__file__)) - self.config_file = 'configs/config-ios-' + arch + '.cmake' - self.toolchain_file = 'toolchains/toolchain-ios-' + arch + '.cmake' - self.output = 'liblinphone-sdk/' + arch + '-apple-darwin.ios' - self.additional_args = [ - '-DLINPHONE_BUILDER_EXTERNAL_SOURCE_PATH=' + - current_path + '/submodules' - ] + def __init__(self, arch): + prepare.Target.__init__(self, 'ios-' + arch) + current_path = os.path.dirname(os.path.realpath(__file__)) + self.config_file = 'configs/config-ios-' + arch + '.cmake' + self.toolchain_file = 'toolchains/toolchain-ios-' + arch + '.cmake' + self.output = 'liblinphone-sdk/' + arch + '-apple-darwin.ios' + self.additional_args = [ + '-DLINPHONE_BUILDER_EXTERNAL_SOURCE_PATH=' + + current_path + '/submodules' + ] - def clean(self): - if os.path.isdir('WORK'): - shutil.rmtree( - 'WORK', ignore_errors=False, onerror=self.handle_remove_read_only) - if os.path.isdir('liblinphone-sdk'): - shutil.rmtree( - 'liblinphone-sdk', ignore_errors=False, onerror=self.handle_remove_read_only) + def clean(self): + if os.path.isdir('WORK'): + shutil.rmtree( + 'WORK', ignore_errors=False, onerror=self.handle_remove_read_only) + if os.path.isdir('liblinphone-sdk'): + shutil.rmtree( + 'liblinphone-sdk', ignore_errors=False, onerror=self.handle_remove_read_only) class IOSi386Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'i386') + def __init__(self): + IOSTarget.__init__(self, 'i386') class IOSx8664Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'x86_64') + def __init__(self): + IOSTarget.__init__(self, 'x86_64') class IOSarmv7Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'armv7') + def __init__(self): + IOSTarget.__init__(self, 'armv7') class IOSarm64Target(IOSTarget): - def __init__(self): - IOSTarget.__init__(self, 'arm64') + def __init__(self): + IOSTarget.__init__(self, 'arm64') targets = {} @@ -91,29 +92,29 @@ platforms = ['all', 'devices', 'simulators'] + archs_device + archs_simu class PlatformListAction(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - if values: - for value in values: - if value not in platforms: - message = ("invalid platform: {0!r} (choose from {1})".format( - value, ', '.join([repr(platform) for platform in platforms]))) - raise argparse.ArgumentError(self, message) - setattr(namespace, self.dest, values) + def __call__(self, parser, namespace, values, option_string=None): + if values: + for value in values: + if value not in platforms: + message = ("invalid platform: {0!r} (choose from {1})".format( + value, ', '.join([repr(platform) for platform in platforms]))) + raise argparse.ArgumentError(self, message) + setattr(namespace, self.dest, values) def warning(platforms): - gpl_third_parties_enabled = False - regex = re.compile("^ENABLE_GPL_THIRD_PARTIES:BOOL=ON") - f = open( - 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]), 'r') - for line in f: - if regex.match(line): - gpl_third_parties_enabled = True - break - f.close() + gpl_third_parties_enabled = False + regex = re.compile("^ENABLE_GPL_THIRD_PARTIES:BOOL=ON") + f = open( + 'WORK/ios-{arch}/cmake/CMakeCache.txt'.format(arch=platforms[0]), 'r') + for line in f: + if regex.match(line): + gpl_third_parties_enabled = True + break + f.close() - if gpl_third_parties_enabled: - print(""" + if gpl_third_parties_enabled: + print(""" *************************************************************************** *************************************************************************** ***** CAUTION, this liblinphone SDK is built using 3rd party GPL code ***** @@ -124,8 +125,8 @@ def warning(platforms): *************************************************************************** *************************************************************************** """) - else: - print(""" + else: + print(""" ***************************************************************** ***************************************************************** ***** Linphone SDK without 3rd party GPL software ***** @@ -138,88 +139,96 @@ def warning(platforms): def extract_libs_list(): - l = [] - # name = libspeexdsp.a; path = "liblinphone-sdk/apple-darwin/lib/libspeexdsp.a"; sourceTree = ""; }; - regex = re.compile("name = (lib(\S+)\.a); path = \"liblinphone-sdk/apple-darwin/") - f = open('linphone.xcodeproj/project.pbxproj', 'r') - lines = f.readlines() - f.close() - for line in lines: - m = regex.search(line) - if m is not None: - l += [m.group(1)] - return list(set(l)) + l = [] + # name = libspeexdsp.a; path = "liblinphone-sdk/apple-darwin/lib/libspeexdsp.a"; sourceTree = ""; }; + regex = re.compile("name = (lib(\S+)\.a); path = \"liblinphone-sdk/apple-darwin/") + f = open('linphone.xcodeproj/project.pbxproj', 'r') + lines = f.readlines() + f.close() + for line in lines: + m = regex.search(line) + if m is not None: + l += [m.group(1)] + return list(set(l)) def install_git_hook(): - git_hook_path = ".git{sep}hooks{sep}pre-commit".format(sep=os.sep) - if os.path.isdir(".git{sep}hooks".format(sep=os.sep)) and not os.path.isfile(git_hook_path): - print("Installing Git pre-commit hook") - shutil.copyfile(".git-pre-commit", git_hook_path) - os.chmod(git_hook_path, 0755) + git_hook_path = ".git{sep}hooks{sep}pre-commit".format(sep=os.sep) + if os.path.isdir(".git{sep}hooks".format(sep=os.sep)) and not os.path.isfile(git_hook_path): + print("Installing Git pre-commit hook") + shutil.copyfile(".git-pre-commit", git_hook_path) + os.chmod(git_hook_path, 0755) def main(argv=None): - if argv is None: - argv = sys.argv - argparser = argparse.ArgumentParser( - description="Prepare build of Linphone and its dependencies.") - argparser.add_argument( - '-c', '-C', '--clean', help="Clean a previous build instead of preparing a build.", action='store_true') - argparser.add_argument( - '-d', '--debug', help="Prepare a debug build, eg. add debug symbols and use no optimizations.", action='store_true') - argparser.add_argument( - '-dv', '--debug-verbose', help="Activate ms_debug logs.", action='store_true') - argparser.add_argument( - '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') - argparser.add_argument('-L', '--list-cmake-variables', - help="List non-advanced CMake cache variables.", action='store_true', - dest='list_cmake_variables') - argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ - 'x86_64', 'devices'], - help="The platform to build for (default is 'x86_64 devices'). Space separated" - " architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) - args, additional_args = argparser.parse_known_args() + if argv is None: + argv = sys.argv + argparser = argparse.ArgumentParser( + description="Prepare build of Linphone and its dependencies.") + argparser.add_argument( + '-c', '-C', '--clean', help="Clean a previous build instead of preparing a build.", action='store_true') + argparser.add_argument( + '-d', '--debug', help="Prepare a debug build, eg. add debug symbols and use no optimizations.", action='store_true') + argparser.add_argument( + '-dv', '--debug-verbose', help="Activate ms_debug logs.", action='store_true') + argparser.add_argument( + '-f', '--force', help="Force preparation, even if working directory already exist.", action='store_true') + argparser.add_argument('-L', '--list-cmake-variables', + help="List non-advanced CMake cache variables.", action='store_true', + dest='list_cmake_variables') + argparser.add_argument('platform', nargs='*', action=PlatformListAction, default=[ + 'x86_64', 'devices'], + help="The platform to build for (default is 'x86_64 devices'). Space separated" + " architectures in list: {0}.".format(', '.join([repr(platform) for platform in platforms]))) + args, additional_args = argparser.parse_known_args() - install_git_hook() + install_git_hook() - selected_platforms = [] - for platform in args.platform: - if platform == 'all': - selected_platforms += archs_device + archs_simu - elif platform == 'devices': - selected_platforms += archs_device - elif platform == 'simulators': - selected_platforms += archs_simu - else: - selected_platforms += [platform] - selected_platforms = list(set(selected_platforms)) + selected_platforms = [] + for platform in args.platform: + if platform == 'all': + selected_platforms += archs_device + archs_simu + elif platform == 'devices': + selected_platforms += archs_device + elif platform == 'simulators': + selected_platforms += archs_simu + else: + selected_platforms += [platform] + selected_platforms = list(set(selected_platforms)) - retcode = 0 - makefile_platforms = [] - for platform in selected_platforms: - target = targets[platform] + retcode = 0 + makefile_platforms = [] + for platform in selected_platforms: + target = targets[platform] - if args.clean: - target.clean() - else: - if args.debug_verbose: - additional_args += ["-DENABLE_DEBUG_LOGS=YES"] - retcode = prepare.run( - target, args.debug, False, args.list_cmake_variables, args.force, additional_args) - if retcode != 0: - return retcode - makefile_platforms += [platform] + if args.clean: + target.clean() + else: + if args.debug_verbose: + additional_args += ["-DENABLE_DEBUG_LOGS=YES"] + retcode = prepare.run( + target, args.debug, False, args.list_cmake_variables, args.force, additional_args) + if retcode != 0: + if retcode == 51: + p = Popen(["make", "help-prepare-options"]) + return retcode + makefile_platforms += [platform] - if makefile_platforms: - libs_list = extract_libs_list() - packages = os.listdir('WORK/ios-' + makefile_platforms[0] + '/Build') - packages.sort() - arch_targets = "" - for arch in makefile_platforms: - arch_targets += """ + if makefile_platforms: + libs_list = extract_libs_list() + packages = os.listdir('WORK/ios-' + makefile_platforms[0] + '/Build') + packages.sort() + arch_targets = "" + for arch in makefile_platforms: + arch_targets += """ {arch}: all-{arch} +package-in-list-%: + if ! grep -q " $* " <<< " $(packages) "; then \\ + echo "$* not in list of available packages: $(packages)"; \\ + exit 3; \\ + fi + {arch}-build: @for package in $(packages); do \\ $(MAKE) {arch}-build-$$package; \\ @@ -235,16 +244,16 @@ def main(argv=None): $(MAKE) {arch}-veryclean-$$package; \\ done -{arch}-build-%: +{arch}-build-%: package-in-list-% rm -f WORK/ios-{arch}/Stamp/EP_$*/EP_$*-update; \\ $(MAKE) -C WORK/ios-{arch}/cmake EP_$* -{arch}-clean-%: +{arch}-clean-%: package-in-list-% $(MAKE) -C WORK/ios-{arch}/Build/$* clean; \\ rm -f WORK/ios-{arch}/Stamp/EP_$*/EP_$*-build; \\ rm -f WORK/ios-{arch}/Stamp/EP_$*/EP_$*-install; -{arch}-veryclean-%: +{arch}-veryclean-%: package-in-list-% cat WORK/ios-{arch}/Build/$*/install_manifest.txt | xargs rm; \\ rm -rf WORK/ios-{arch}/Build/$*/*; \\ rm -f WORK/ios-{arch}/Stamp/EP_$*/*; \\ @@ -276,17 +285,17 @@ def main(argv=None): rm -f WORK/ios-{arch}/Stamp/EP_vpx/*; \\ echo "Run 'make {arch}-build-vpx' to rebuild vpx correctly."; """.format(arch=arch) - multiarch = "" - for arch in makefile_platforms[1:]: - multiarch += \ - """ if test -f "$${arch}_path"; then \\ + multiarch = "" + for arch in makefile_platforms[1:]: + multiarch += \ + """ if test -f "$${arch}_path"; then \\ all_paths=`echo $$all_paths $${arch}_path`; \\ all_archs="$$all_archs,{arch}" ; \\ else \\ echo "WARNING: archive `basename $$archive` exists in {first_arch} tree but does not exists in {arch} tree: $${arch}_path."; \\ fi; \\ """.format(first_arch=makefile_platforms[0], arch=arch) - makefile = """ + makefile = """ archs={archs} packages={packages} libs_list={libs_list} @@ -303,19 +312,19 @@ all-%: done $(MAKE) -C WORK/ios-$*/cmake -build-%: +build-%: package-in-list-% @for arch in $(archs); do \\ echo "==== starting build of $* for arch $$arch ===="; \\ $(MAKE) $$arch-build-$*; \\ done -clean-%: +clean-%: package-in-list-% @for arch in $(archs); do \\ echo "==== starting clean of $* for arch $$arch ===="; \\ $(MAKE) $$arch-clean-$*; \\ done -veryclean-%: +veryclean-%: package-in-list-% @for arch in $(archs); do \\ echo "==== starting veryclean of $* for arch $$arch ===="; \\ $(MAKE) $$arch-veryclean-$*; \\ @@ -380,7 +389,12 @@ push-transifex: zipres: @tar -czf ios_assets.tar.gz Resources iTunesArtwork -help: +help-prepare-options: + @echo "prepare.py was previously executed with the following options:" + @echo " {options}" + +help: help-prepare-options + @echo "" @echo "(please read the README.md file first)" @echo "" @echo "Available architectures: {archs}" @@ -401,16 +415,17 @@ help: @echo "" @echo " * sdk : re-add all generated libraries to the SDK. Use this only after a full build." @echo " * libs : after a rebuild of a subpackage, will mix the new libs in liblinphone-sdk/apple-darwin directory" -""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), first_arch=makefile_platforms[0], - arch_targets=arch_targets, packages=' '.join(packages), libs_list=' '.join(libs_list), multiarch=multiarch) - f = open('Makefile', 'w') - f.write(makefile) - f.close() - warning(makefile_platforms) - elif os.path.isfile('Makefile'): - os.remove('Makefile') +""".format(archs=' '.join(makefile_platforms), arch_opts='|'.join(makefile_platforms), + first_arch=makefile_platforms[0], options=' '.join(sys.argv), + arch_targets=arch_targets, packages=' '.join(packages), libs_list=' '.join(libs_list), multiarch=multiarch) + f = open('Makefile', 'w') + f.write(makefile) + f.close() + warning(makefile_platforms) + elif os.path.isfile('Makefile'): + os.remove('Makefile') - return retcode + return retcode if __name__ == "__main__": - sys.exit(main()) + sys.exit(main()) diff --git a/submodules/cmake-builder b/submodules/cmake-builder index cf6ad6e18..3955daa45 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit cf6ad6e18ce9707e8236a6ab2c0fd789bdb9287d +Subproject commit 3955daa45fa1f0eeb13b041560f78cfa7450968b diff --git a/submodules/libilbc-rfc3951 b/submodules/libilbc-rfc3951 index bc20f1196..a6bb1eb6d 160000 --- a/submodules/libilbc-rfc3951 +++ b/submodules/libilbc-rfc3951 @@ -1 +1 @@ -Subproject commit bc20f11963878a1f32511de59b05490093e5c9b8 +Subproject commit a6bb1eb6dab5541cdded6a1f0326539234954c5d From 62b6669c1a559499c1519ac4a6ef48d68efa216c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 16 Jun 2015 14:53:01 +0200 Subject: [PATCH 28/36] FileTransfer: fix crash when deleting a chat room with pending transfers --- Classes/ChatRoomTableViewController.m | 1 - Classes/ChatTableViewController.m | 12 ++++++++++-- Classes/Utils/FileTransferDelegate.m | 4 ++-- KifTests/ChatTester.m | 7 +++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 2cc654e1e..425b06662 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -194,7 +194,6 @@ [tableView beginUpdates]; LinphoneChatMessage *chat = ms_list_nth_data(self->messageList, (int)[indexPath row]); if( chat ){ - linphone_chat_room_delete_message(chatRoom, chat); messageList = ms_list_remove(messageList, chat); diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index c5f38c70a..e6ce9be78 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -20,6 +20,8 @@ #import "ChatTableViewController.h" #import "UIChatCell.h" +#import "FileTransferDelegate.h" + #import "linphone/linphonecore.h" #import "PhoneMainView.h" #import "UACellBackgroundView.h" @@ -171,8 +173,14 @@ static void chatTable_free_chatrooms(void *data){ linphone_chat_message_unref(last_msg); linphone_chat_room_set_user_data(chatRoom, NULL); } - linphone_chat_room_delete_history(chatRoom); - linphone_chat_room_unref(chatRoom); + + for (FileTransferDelegate *ftd in [[LinphoneManager instance] fileTransferDelegates]) { + if (linphone_chat_message_get_chat_room(ftd.message) == chatRoom) { + [ftd cancel]; + } + } + linphone_chat_room_delete_history(chatRoom); + linphone_chat_room_unref(chatRoom); data = ms_list_remove(data, chatRoom); // will force a call to [self loadData] diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m index 6a6adf1ef..36419cbf4 100644 --- a/Classes/Utils/FileTransferDelegate.m +++ b/Classes/Utils/FileTransferDelegate.m @@ -73,7 +73,7 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con CFRelease((__bridge CFTypeRef)thiz); }]; } else { - LOGI(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content), + LOGD(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content), linphone_content_get_size(content), [thiz.data length], size); [thiz.data appendBytes:linphone_buffer_get_string_content(buffer) length:size]; [[NSNotificationCenter defaultCenter] @@ -97,7 +97,7 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m @"state" : @(linphone_chat_message_get_state(message)), @"progress" : @(offset * 1.f / total), }]; - LOGI(@"Transfer of %s (%d bytes): already sent %ld, remaining %ld", linphone_content_get_name(content), total, + LOGD(@"Transfer of %s (%d bytes): already sent %ld, remaining %ld", linphone_content_get_name(content), total, offset, remaining); [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneFileTransferSendUpdate object:thiz diff --git a/KifTests/ChatTester.m b/KifTests/ChatTester.m index 2b890443a..76cd623c5 100644 --- a/KifTests/ChatTester.m +++ b/KifTests/ChatTester.m @@ -211,6 +211,13 @@ - (void)downloadImage { [self uploadImage]; + // wait for the upload to terminate... + for (int i = 0; i < 15; i++) { + [tester waitForTimeInterval:1.f]; + if ([[[LinphoneManager instance] fileTransferDelegates] count] == 0) + break; + } + [tester waitForViewWithAccessibilityLabel:LOCALIZED(@"Download")]; [tester tapViewWithAccessibilityLabel:LOCALIZED(@"Download")]; [tester waitForTimeInterval:.5f]; // just wait a few secs to start download XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 1); From 016fa44f62e354bf06b2307db5821f4bf34e550e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 16 Jun 2015 10:49:48 +0200 Subject: [PATCH 29/36] InAppSettings: reorder code by section --- Classes/LinphoneCoreSettingsStore.h | 23 +- Classes/LinphoneCoreSettingsStore.m | 1021 ++++++++++--------- Classes/LinphoneManager.h | 24 +- Classes/LinphoneManager.m | 109 +- Classes/SettingsViewController.m | 2 - Settings/InAppSettings.bundle/Audio.plist | 30 - Settings/InAppSettings.bundle/Network.plist | 50 +- Settings/InAppSettings.bundle/Root.plist | 2 +- 8 files changed, 645 insertions(+), 616 deletions(-) diff --git a/Classes/LinphoneCoreSettingsStore.h b/Classes/LinphoneCoreSettingsStore.h index ee73e33ea..224b8f679 100644 --- a/Classes/LinphoneCoreSettingsStore.h +++ b/Classes/LinphoneCoreSettingsStore.h @@ -4,18 +4,18 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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 + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ + */ #import #import "IASKSettingsStore.h" @@ -28,7 +28,6 @@ NSDictionary *changedDict; } -- (void)synchronizeAccount; - (void)transformLinphoneCoreToKeys; @end diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 471fa9d3a..35ffcf31d 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -18,6 +18,7 @@ */ #import "LinphoneCoreSettingsStore.h" +#import "DTAlertView.h" #include "linphone/lpconfig.h" @@ -27,7 +28,7 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); - (id)init { self = [super init]; - if (self){ + if (self) { dict = [[NSMutableDictionary alloc] init]; changedDict = [[NSMutableDictionary alloc] init]; [self transformLinphoneCoreToKeys]; @@ -35,192 +36,187 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); return self; } - -- (void)transformKeysToLinphoneCore { - //LinphoneCore *lc=[LinphoneManager getLc]; - -} - -- (void)setString:(const char*)value forKey:(NSString*)key { - id obj=Nil; - if (value) obj=[[NSString alloc] initWithCString:value encoding:[NSString defaultCStringEncoding] ]; +- (void)setCString:(const char *)value forKey:(NSString *)key { + id obj = Nil; + if (value) + obj = [[NSString alloc] initWithCString:value encoding:[NSString defaultCStringEncoding]]; [self setObject:obj forKey:key]; } -- (NSString*)stringForKey:(NSString*) key { - return [self objectForKey: key]; +- (NSString *)stringForKey:(NSString *)key { + return [self objectForKey:key]; } -- (void)transformCodecsToKeys: (const MSList *)codecs { - LinphoneCore *lc=[LinphoneManager getLc]; - const MSList *elem=codecs; - for(;elem!=NULL;elem=elem->next){ - PayloadType *pt=(PayloadType*)elem->data; - NSString *pref=[LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate]; - if (pref){ - bool_t value = linphone_core_payload_type_enabled(lc,pt); - [self setBool:value forKey: pref]; - }else{ - LOGW(@"Codec %s/%i supported by core is not shown in iOS app config view.", - pt->mime_type,pt->clock_rate); +- (void)setObject:(id)value forKey:(NSString *)key { + [dict setValue:value forKey:key]; + [changedDict setValue:[NSNumber numberWithBool:TRUE] forKey:key]; +} + +- (id)objectForKey:(NSString *)key { + return [dict valueForKey:key]; +} + +- (BOOL)valueChangedForKey:(NSString *)key { + return [[changedDict valueForKey:key] boolValue]; +} + ++ (int)validPort:(int)port { + if (port < 0) { + return 0; + } + if (port > 65535) { + return 65535; + } + return port; +} + ++ (BOOL)parsePortRange:(NSString *)text minPort:(int *)minPort maxPort:(int *)maxPort { + NSError *error = nil; + *minPort = -1; + *maxPort = -1; + NSRegularExpression *regex = + [NSRegularExpression regularExpressionWithPattern:@"([0-9]+)(([^0-9]+)([0-9]+))?" options:0 error:&error]; + if (error != NULL) + return FALSE; + NSArray *matches = [regex matchesInString:text options:0 range:NSMakeRange(0, [text length])]; + if ([matches count] == 1) { + NSTextCheckingResult *match = [matches objectAtIndex:0]; + bool range = [match rangeAtIndex:2].length > 0; + if (!range) { + NSRange rangeMinPort = [match rangeAtIndex:1]; + *minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]]; + *maxPort = *minPort; + return TRUE; + } else { + NSRange rangeMinPort = [match rangeAtIndex:1]; + *minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]]; + NSRange rangeMaxPort = [match rangeAtIndex:4]; + *maxPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMaxPort] intValue]]; + if (*minPort > *maxPort) { + *minPort = *maxPort; + } + return TRUE; + } + } + return FALSE; +} + +- (void)transformCodecsToKeys:(const MSList *)codecs { + LinphoneCore *lc = [LinphoneManager getLc]; + + const MSList *elem = codecs; + for (; elem != NULL; elem = elem->next) { + PayloadType *pt = (PayloadType *)elem->data; + NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate]; + if (pref) { + bool_t value = linphone_core_payload_type_enabled(lc, pt); + [self setBool:value forKey:pref]; + } else { + LOGW(@"Codec %s/%i supported by core is not shown in iOS app config view.", pt->mime_type, pt->clock_rate); } } } - (void)transformLinphoneCoreToKeys { - LinphoneCore *lc=[LinphoneManager getLc]; - LinphoneProxyConfig *cfg=NULL; - LpConfig* conf = linphone_core_get_config(lc); - linphone_core_get_default_proxy(lc,&cfg); - if (cfg){ - const char *identity=linphone_proxy_config_get_identity(cfg); - LinphoneAddress *addr=linphone_address_new(identity); - if (addr){ - const char *proxy=linphone_proxy_config_get_addr(cfg); - LinphoneAddress *proxy_addr=linphone_address_new(proxy); - int port=linphone_address_get_port(proxy_addr); + LinphoneManager *lm = [LinphoneManager instance]; + LinphoneCore *lc = [LinphoneManager getLc]; - [self setString: linphone_address_get_username(addr) forKey:@"username_preference"]; - [self setString: linphone_address_get_domain(addr) forKey:@"domain_preference"]; - [self setInteger: linphone_proxy_config_get_expires(cfg) forKey:@"expire_preference"]; - [self setString: linphone_proxy_config_get_dial_prefix(cfg) forKey:@"prefix_preference"]; - if (strcmp(linphone_address_get_domain(addr),linphone_address_get_domain(proxy_addr))!=0 || port>0){ - char tmp[256]={0}; - if (port>0) { - snprintf(tmp,sizeof(tmp)-1,"%s:%i",linphone_address_get_domain(proxy_addr),port); - }else snprintf(tmp,sizeof(tmp)-1,"%s",linphone_address_get_domain(proxy_addr)); - [self setString:tmp forKey:@"proxy_preference"]; + // root section + { + LinphoneProxyConfig *cfg = NULL; + linphone_core_get_default_proxy(lc, &cfg); + if (cfg) { + const char *identity = linphone_proxy_config_get_identity(cfg); + LinphoneAddress *addr = linphone_address_new(identity); + if (addr) { + const char *proxy = linphone_proxy_config_get_addr(cfg); + LinphoneAddress *proxy_addr = linphone_address_new(proxy); + int port = linphone_address_get_port(proxy_addr); + + [self setCString:linphone_address_get_username(addr) forKey:@"username_preference"]; + [self setCString:linphone_address_get_domain(addr) forKey:@"domain_preference"]; + if (strcmp(linphone_address_get_domain(addr), linphone_address_get_domain(proxy_addr)) != 0 || + port > 0) { + char tmp[256] = {0}; + if (port > 0) { + snprintf(tmp, sizeof(tmp) - 1, "%s:%i", linphone_address_get_domain(proxy_addr), port); + } else + snprintf(tmp, sizeof(tmp) - 1, "%s", linphone_address_get_domain(proxy_addr)); + [self setCString:tmp forKey:@"proxy_preference"]; + } + const char *tname = "udp"; + switch (linphone_address_get_transport(proxy_addr)) { + case LinphoneTransportTcp: + tname = "tcp"; + break; + case LinphoneTransportTls: + tname = "tls"; + break; + default: + break; + } + linphone_address_destroy(addr); + linphone_address_destroy(proxy_addr); + + [self setCString:tname forKey:@"transport_preference"]; + [self setBool:(linphone_proxy_config_get_route(cfg) != NULL)forKey:@"outbound_proxy_preference"]; + [self setBool:linphone_proxy_config_avpf_enabled(cfg) forKey:@"avpf_preference"]; + [self setBool:linphone_core_video_enabled(lc) forKey:@"enable_video_preference"]; + + // actually in Advanced section but proxy config dependent + [self setInteger:linphone_proxy_config_get_expires(cfg) forKey:@"expire_preference"]; + // actually in Call section but proxy config dependent + [self setCString:linphone_proxy_config_get_dial_prefix(cfg) forKey:@"prefix_preference"]; + // actually in Call section but proxy config dependent + [self setBool:linphone_proxy_config_get_dial_escape_plus(cfg) forKey:@"substitute_+_by_00_preference"]; } - - const char* tname = "udp"; - switch (linphone_address_get_transport(proxy_addr)) { - case LinphoneTransportTcp: tname = "tcp"; break; - case LinphoneTransportTls: tname = "tls"; break; - default: break; - } - [self setString:tname forKey:@"transport_preference"]; - - linphone_address_destroy(addr); - linphone_address_destroy(proxy_addr); - - [self setBool:(linphone_proxy_config_get_route(cfg)!=NULL) forKey:@"outbound_proxy_preference"]; - [self setBool:linphone_proxy_config_get_dial_escape_plus(cfg) forKey:@"substitute_+_by_00_preference"]; - [self setBool:linphone_proxy_config_avpf_enabled(cfg) forKey:@"avpf_preference"]; - + } else { + [self setObject:@"" forKey:@"username_preference"]; + [self setObject:@"" forKey:@"password_preference"]; + [self setObject:@"" forKey:@"domain_preference"]; + [self setObject:@"" forKey:@"proxy_preference"]; + [self setCString:"udp" forKey:@"transport_preference"]; + [self setBool:FALSE forKey:@"outbound_proxy_preference"]; + [self setBool:FALSE forKey:@"avpf_preference"]; + // actually in Advanced section but proxy config dependent + [self setInteger:[lm lpConfigIntForKey:@"reg_expires" forSection:@"default_values" withDefault:600] + forKey:@"expire_preference"]; } - } else { - [self setInteger: lp_config_get_int(conf,"default_values","reg_expires", 600) forKey:@"expire_preference"]; - [self setObject:@"" forKey:@"username_preference"]; - [self setObject:@"" forKey:@"domain_preference"]; - [self setObject:@"" forKey:@"proxy_preference"]; - [self setObject:@"" forKey:@"password_preference"]; - [self setBool:FALSE forKey:@"outbound_proxy_preference"]; - [self setString:"udp" forKey:@"transport_preference"]; - [self setBool:FALSE forKey:@"avpf_preference"]; - } - - [self setBool:lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "pushnotification_preference", 0) forKey:@"pushnotification_preference"]; - { - LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc); - if(parsed != NULL) { - [self setString: linphone_address_get_display_name(parsed) forKey:@"primary_displayname_preference"]; - [self setString: linphone_address_get_username(parsed) forKey:@"primary_username_preference"]; - } - linphone_address_destroy(parsed); - } - { - { - int minPort, maxPort; - linphone_core_get_audio_port_range(lc, &minPort, &maxPort); - if(minPort != maxPort) - [self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"audio_port_preference"]; - else - [self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"audio_port_preference"]; - } - { - int minPort, maxPort; - linphone_core_get_video_port_range(lc, &minPort, &maxPort); - if(minPort != maxPort) - [self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"video_port_preference"]; - else - [self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"video_port_preference"]; - } - } - { - [self setInteger: linphone_core_get_upload_bandwidth(lc) forKey:@"upload_bandwidth_preference"]; - [self setInteger: linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"]; - } - { - [self setFloat:linphone_core_get_playback_gain_db(lc) forKey:@"playback_gain_preference"]; - [self setFloat:linphone_core_get_mic_gain_db(lc) forKey:@"microphone_gain_preference"]; - } - { - int port = lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "port_preference", 5060); - [self setInteger:port forKey:@"port_preference"]; - int random_port_preference = lp_config_get_int(conf,LINPHONERC_APPLICATION_KEY,"random_port_preference", 1); - [self setInteger:random_port_preference forKey:@"random_port_preference"]; - } - { LinphoneAuthInfo *ai; - const MSList *elem=linphone_core_get_auth_info_list(lc); - if (elem && (ai=(LinphoneAuthInfo*)elem->data)){ - [self setString: linphone_auth_info_get_passwd(ai) forKey:@"password_preference"]; - [self setString: linphone_auth_info_get_ha1(ai) forKey:@"ha1_preference"]; // hidden but useful if provisioned - [self setString:linphone_auth_info_get_userid(ai) forKey:@"userid_preference"]; + const MSList *elem = linphone_core_get_auth_info_list(lc); + if (elem && (ai = (LinphoneAuthInfo *)elem->data)) { + [self setCString:linphone_auth_info_get_userid(ai) forKey:@"userid_preference"]; + [self setCString:linphone_auth_info_get_passwd(ai) forKey:@"password_preference"]; + // hidden but useful if provisioned + [self setCString:linphone_auth_info_get_ha1(ai) forKey:@"ha1_preference"]; } - } - { - [self setString: linphone_core_get_stun_server(lc) forKey:@"stun_preference"]; - [self setBool:linphone_core_get_firewall_policy(lc)==LinphonePolicyUseIce forKey:@"ice_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"]; } + // audio section { - [self transformCodecsToKeys: linphone_core_get_audio_codecs(lc)]; - [self transformCodecsToKeys: linphone_core_get_video_codecs(lc)]; - [self setBool:linphone_core_adaptive_rate_control_enabled(lc) forKey:@"adaptive_rate_control_preference"]; - [self setString:linphone_core_get_adaptive_rate_algorithm(lc) forKey:@"adaptive_rate_algorithm_preference"]; - - [self setInteger:lp_config_get_int(conf, "audio", "codec_bitrate_limit", kLinphoneAudioVbrCodecDefaultBitrate) forKey:@"audio_codec_bitrate_limit_preference"]; - [self setInteger:lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "voiceproc_preference", 1) forKey:@"voiceproc_preference"]; - [self setInteger:lp_config_get_int(conf, "sound", "eq_active", 0) forKey:@"eq_active"]; + [self transformCodecsToKeys:linphone_core_get_audio_codecs(lc)]; + [self setFloat:linphone_core_get_playback_gain_db(lc) forKey:@"playback_gain_preference"]; + [self setFloat:linphone_core_get_mic_gain_db(lc) forKey:@"microphone_gain_preference"]; + [self setInteger:[lm lpConfigIntForKey:@"codec_bitrate_limit" + forSection:@"audio" + withDefault:kLinphoneAudioVbrCodecDefaultBitrate] + forKey:@"audio_codec_bitrate_limit_preference"]; + [self setInteger:[lm lpConfigIntForKey:@"voiceproc_preference" withDefault:1] forKey:@"voiceproc_preference"]; + [self setInteger:[lm lpConfigIntForKey:@"eq_active" forSection:@"sound" withDefault:0] forKey:@"eq_active"]; } - [self setBool:lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "advanced_account_preference", 0) forKey:@"advanced_account_preference"]; - + // video section { - LinphoneMediaEncryption menc=linphone_core_get_media_encryption(lc); - const char *val; - switch(menc){ - case LinphoneMediaEncryptionSRTP: val="SRTP"; break; - case LinphoneMediaEncryptionZRTP: val="ZRTP"; break; - case LinphoneMediaEncryptionDTLS: val="DTLS"; break; - case LinphoneMediaEncryptionNone: val="None"; break; - } - [self setString:val forKey:@"media_encryption_preference"]; - } - [self setBool: lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "edge_opt_preference", 0) forKey:@"edge_opt_preference"]; - [self setBool: lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "enable_first_login_view_preference", 0) forKey:@"enable_first_login_view_preference"]; - [self setBool: lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "debugenable_preference", 0) forKey:@"debugenable_preference"]; - [self setBool: lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "animations_preference", 1) forKey:@"animations_preference"]; - [self setBool: lp_config_get_int(conf, LINPHONERC_APPLICATION_KEY, "wifi_only_preference", 0) forKey:@"wifi_only_preference"]; - [self setString: lp_config_get_string(conf, LINPHONERC_APPLICATION_KEY, "sharing_server_preference", NULL) forKey:@"sharing_server_preference"]; - [self setBool:lp_config_get_int(conf, "sip", "use_ipv6", 0) forKey:@"use_ipv6"]; + [self transformCodecsToKeys:linphone_core_get_video_codecs(lc)]; - - [self setBool: lp_config_get_int(conf,LINPHONERC_APPLICATION_KEY,"start_at_boot_preference",1) forKey:@"start_at_boot_preference"]; - [self setBool: lp_config_get_int(conf,LINPHONERC_APPLICATION_KEY,"backgroundmode_preference",1) forKey:@"backgroundmode_preference"]; - [self setBool: lp_config_get_int(conf,LINPHONERC_APPLICATION_KEY,"autoanswer_notif_preference",1) forKey:@"autoanswer_notif_preference"]; - - - { const LinphoneVideoPolicy *pol; - [self setBool: linphone_core_video_enabled(lc) forKey:@"enable_video_preference"]; - pol=linphone_core_get_video_policy(lc); - [self setBool:(pol->automatically_initiate) forKey:@"start_video_preference"]; - [self setBool:(pol->automatically_accept) forKey:@"accept_video_preference"]; + pol = linphone_core_get_video_policy(lc); + [self setBool:(pol->automatically_initiate)forKey:@"start_video_preference"]; + [self setBool:(pol->automatically_accept)forKey:@"accept_video_preference"]; [self setBool:linphone_core_self_view_enabled(lc) forKey:@"self_video_preference"]; - BOOL previewEnabled=lp_config_get_int(conf,LINPHONERC_APPLICATION_KEY,"preview_preference",1); + BOOL previewEnabled = [lm lpConfigBoolForKey:@"preview_preference" withDefault:YES]; [self setBool:previewEnabled forKey:@"preview_preference"]; MSVideoSize vsize = linphone_core_get_preferred_video_size(lc); int index; @@ -233,6 +229,8 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); } [self setInteger:index forKey:@"video_preferred_size_preference"]; } + + // call section { [self setBool:linphone_core_get_use_info_for_dtmf(lc) forKey:@"sipinfo_dtmf_preference"]; [self setBool:linphone_core_get_use_rfc2833_for_dtmf(lc) forKey:@"rfc_dtmf_preference"]; @@ -241,21 +239,96 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [self setInteger:linphone_core_get_in_call_timeout(lc) forKey:@"in_call_timeout_preference"]; } - // Tunnel - if (linphone_core_tunnel_available()){ + // network section + { + [self setBool:[lm lpConfigBoolForKey:@"edge_opt_preference" withDefault:NO] forKey:@"edge_opt_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"wifi_only_preference" withDefault:NO] forKey:@"wifi_only_preference"]; + [self setCString:linphone_core_get_stun_server(lc) forKey:@"stun_preference"]; + [self setBool:linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce forKey:@"ice_preference"]; + int random_port_preference = [lm lpConfigIntForKey:@"random_port_preference" withDefault:1]; + [self setInteger:random_port_preference forKey:@"random_port_preference"]; + int port = [lm lpConfigIntForKey:@"port_preference" withDefault:5060]; + [self setInteger:port forKey:@"port_preference"]; + { + int minPort, maxPort; + linphone_core_get_audio_port_range(lc, &minPort, &maxPort); + if (minPort != maxPort) + [self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"audio_port_preference"]; + else + [self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"audio_port_preference"]; + } + { + int minPort, maxPort; + linphone_core_get_video_port_range(lc, &minPort, &maxPort); + if (minPort != maxPort) + [self setObject:[NSString stringWithFormat:@"%d-%d", minPort, maxPort] forKey:@"video_port_preference"]; + else + [self setObject:[NSString stringWithFormat:@"%d", minPort] forKey:@"video_port_preference"]; + } + [self setBool:[lm lpConfigBoolForKey:@"use_ipv6" withDefault:NO] forKey:@"use_ipv6"]; + LinphoneMediaEncryption menc = linphone_core_get_media_encryption(lc); + const char *val; + switch (menc) { + case LinphoneMediaEncryptionSRTP: + val = "SRTP"; + break; + case LinphoneMediaEncryptionZRTP: + val = "ZRTP"; + break; + case LinphoneMediaEncryptionDTLS: + val = "DTLS"; + break; + case LinphoneMediaEncryptionNone: + val = "None"; + break; + } + [self setCString:val forKey:@"media_encryption_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"pushnotification_preference" withDefault:NO] + forKey:@"pushnotification_preference"]; + [self setInteger:linphone_core_get_upload_bandwidth(lc) forKey:@"upload_bandwidth_preference"]; + [self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"]; + [self setBool:linphone_core_adaptive_rate_control_enabled(lc) forKey:@"adaptive_rate_control_preference"]; + [self setCString:linphone_core_get_adaptive_rate_algorithm(lc) forKey:@"adaptive_rate_algorithm_preference"]; + } + + // tunnel section + if (linphone_core_tunnel_available()) { LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]); - [self setString:lp_config_get_string(linphone_core_get_config(lc), LINPHONERC_APPLICATION_KEY, "tunnel_mode_preference", "off") forKey:@"tunnel_mode_preference"]; - const MSList* configs = linphone_tunnel_get_servers(tunnel); - if(configs != NULL) { + [self setObject:[lm lpConfigStringForKey:@"tunnel_mode_preference" withDefault:@"off"] + forKey:@"tunnel_mode_preference"]; + const MSList *configs = linphone_tunnel_get_servers(tunnel); + if (configs != NULL) { LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data; - [self setString:linphone_tunnel_config_get_host(ltc) forKey:@"tunnel_address_preference"]; + [self setCString:linphone_tunnel_config_get_host(ltc) forKey:@"tunnel_address_preference"]; [self setInteger:linphone_tunnel_config_get_port(ltc) forKey:@"tunnel_port_preference"]; } else { - [self setString:"" forKey:@"tunnel_address_preference"]; + [self setCString:"" forKey:@"tunnel_address_preference"]; [self setInteger:443 forKey:@"tunnel_port_preference"]; } } + // advanced section + { + [self setBool:[lm lpConfigBoolForKey:@"debugenable_preference" withDefault:NO] + forKey:@"debugenable_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"animations_preference" withDefault:NO] forKey:@"animations_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"backgroundmode_preference" withDefault:NO] + forKey:@"backgroundmode_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"start_at_boot_preference" withDefault:NO] + forKey:@"start_at_boot_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"autoanswer_notif_preference" withDefault:NO] + forKey:@"autoanswer_notif_preference"]; + [self setBool:[lm lpConfigBoolForKey:@"enable_first_login_view_preference" withDefault:NO] + forKey:@"enable_first_login_view_preference"]; + LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc); + if (parsed != NULL) { + [self setCString:linphone_address_get_display_name(parsed) forKey:@"primary_displayname_preference"]; + [self setCString:linphone_address_get_username(parsed) forKey:@"primary_username_preference"]; + } + linphone_address_destroy(parsed); + [self setObject:[lm lpConfigStringForKey:@"sharing_server_preference"] forKey:@"sharing_server_preference"]; + } + changedDict = [[NSMutableDictionary alloc] init]; // Post event @@ -263,48 +336,31 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneLogsUpdate object:self userInfo:eventDic]; } -- (void)setObject:(id)value forKey:(NSString *)key { - [dict setValue:value forKey:key]; - [changedDict setValue:[NSNumber numberWithBool:TRUE] forKey:key]; -} - -- (id)objectForKey:(NSString*)key { - return [dict valueForKey:key]; -} - -- (BOOL)valueChangedForKey:(NSString*)key { - return [[changedDict valueForKey:key] boolValue]; -} - -- (void)alertAccountError:(NSString*)error { - UIAlertView* alertview = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) +- (void)alertAccountError:(NSString *)error { + UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) message:error delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", nil) - otherButtonTitles: nil]; + otherButtonTitles:nil]; [alertview show]; } -+ (BOOL)hasSipPrefix:(NSString*)str { - return [str hasPrefix:@"sip:"] || [str hasPrefix:@"sips:"]; -} - - (void)synchronizeAccount { + LinphoneManager *lm = [LinphoneManager instance]; LinphoneCore *lc = [LinphoneManager getLc]; - LpConfig* conf = linphone_core_get_config(lc); - LinphoneProxyConfig* proxyCfg = NULL; + LinphoneProxyConfig *proxyCfg = NULL; BOOL isEditing = FALSE; - NSString* error = nil; + NSString *error = nil; int port_preference = [self integerForKey:@"port_preference"]; BOOL random_port_preference = [self boolForKey:@"random_port_preference"]; - lp_config_set_int(conf, LINPHONERC_APPLICATION_KEY, "random_port_preference", random_port_preference); - if(random_port_preference) { + [lm lpConfigSetInt:random_port_preference forKey:@"random_port_preference"]; + if (random_port_preference) { port_preference = -1; } - LCSipTransports transportValue={ port_preference, port_preference, -1, -1 }; + LCSipTransports transportValue = {port_preference, port_preference, -1, -1}; // will also update the sip_*_port section of the config if (linphone_core_set_sip_transports(lc, &transportValue)) { @@ -314,54 +370,55 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); port_preference = linphone_core_get_sip_port(lc); [self setInteger:port_preference forKey:@"port_preference"]; // Update back preference - BOOL enable_ipv6 = [self boolForKey:@"use_ipv6"]; - lp_config_set_int(conf, "sip", "use_ipv6", enable_ipv6); - if( linphone_core_ipv6_enabled(lc) != enable_ipv6){ - LOGD(@"%@ IPV6", enable_ipv6?@"ENABLING":@"DISABLING"); + [lm lpConfigSetBool:enable_ipv6 forKey:@"use_ipv6" forSection:@"sip"]; + if (linphone_core_ipv6_enabled(lc) != enable_ipv6) { + LOGD(@"%@ IPV6", enable_ipv6 ? @"ENABLING" : @"DISABLING"); linphone_core_enable_ipv6(lc, enable_ipv6); } + // configure sip account - //configure sip account + // mandatory parameters + NSString *username = [self stringForKey:@"username_preference"]; + NSString *userID = [self stringForKey:@"userid_preference"]; + NSString *domain = [self stringForKey:@"domain_preference"]; + NSString *transport = [self stringForKey:@"transport_preference"]; + NSString *accountHa1 = [self stringForKey:@"ha1_preference"]; + NSString *accountPassword = [self stringForKey:@"password_preference"]; + bool isOutboundProxy = [self boolForKey:@"outbound_proxy_preference"]; + BOOL use_avpf = [self boolForKey:@"avpf_preference"]; - //mandatory parameters - NSString* username = [self stringForKey:@"username_preference"]; - NSString* userID = [self stringForKey:@"userid_preference"]; - NSString* domain = [self stringForKey:@"domain_preference"]; - NSString* transport = [self stringForKey:@"transport_preference"]; - NSString* accountHa1 = [self stringForKey:@"ha1_preference"]; - NSString* accountPassword = [self stringForKey:@"password_preference"]; - bool isOutboundProxy = [self boolForKey:@"outbound_proxy_preference"]; - BOOL use_avpf = [self boolForKey:@"avpf_preference"]; + if (username && [username length] > 0 && domain && [domain length] > 0) { + int expire = [self integerForKey:@"expire_preference"]; + BOOL isWifiOnly = [self boolForKey:@"wifi_only_preference"]; + BOOL pushnotification = [self boolForKey:@"pushnotification_preference"]; + NSString *prefix = [self stringForKey:@"prefix_preference"]; + NSString *proxyAddress = [self stringForKey:@"proxy_preference"]; - if (username && [username length] >0 && domain && [domain length]>0) { - int expire = [self integerForKey:@"expire_preference"]; - BOOL isWifiOnly = [self boolForKey:@"wifi_only_preference"]; - BOOL pushnotification = [self boolForKey:@"pushnotification_preference"]; - NSString* prefix = [self stringForKey:@"prefix_preference"]; - NSString* proxyAddress = [self stringForKey:@"proxy_preference"]; + LinphoneAuthInfo *info = NULL; + const char *route = NULL; - LinphoneAuthInfo *info = NULL; - const char* route = NULL; + if (isWifiOnly && [LinphoneManager instance].connectivity == wwan) + expire = 0; - if( isWifiOnly && [LinphoneManager instance].connectivity == wwan ) expire = 0; - - if ((!proxyAddress || [proxyAddress length] <1 ) && domain) { + if ((!proxyAddress || [proxyAddress length] < 1) && domain) { proxyAddress = domain; - } - - if( ![LinphoneCoreSettingsStore hasSipPrefix:proxyAddress] ) { - proxyAddress = [NSString stringWithFormat:@"sip:%@",proxyAddress]; } - char* proxy = ms_strdup([proxyAddress cStringUsingEncoding:[NSString defaultCStringEncoding]]); - LinphoneAddress* proxy_addr = linphone_address_new(proxy); + if (![proxyAddress hasPrefix:@"sip:"] && ![proxyAddress hasPrefix:@"sips:"]) { + proxyAddress = [NSString stringWithFormat:@"sip:%@", proxyAddress]; + } - if( proxy_addr ){ + char *proxy = ms_strdup([proxyAddress cStringUsingEncoding:[NSString defaultCStringEncoding]]); + LinphoneAddress *proxy_addr = linphone_address_new(proxy); + + if (proxy_addr) { LinphoneTransportType type = LinphoneTransportUdp; - if ( [transport isEqualToString:@"tcp"] ) type = LinphoneTransportTcp; - else if ( [transport isEqualToString:@"tls"] ) type = LinphoneTransportTls; + if ([transport isEqualToString:@"tcp"]) + type = LinphoneTransportTcp; + else if ([transport isEqualToString:@"tls"]) + type = LinphoneTransportTls; linphone_address_set_transport(proxy_addr, type); ms_free(proxy); @@ -369,11 +426,11 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); } // use proxy as route if outbound_proxy is enabled - route = isOutboundProxy? proxy : NULL; + route = isOutboundProxy ? proxy : NULL; - //possible valid config detected, try to modify current proxy or create new one if none existing + // possible valid config detected, try to modify current proxy or create new one if none existing linphone_core_get_default_proxy(lc, &proxyCfg); - if( proxyCfg == NULL ){ + if (proxyCfg == NULL) { proxyCfg = linphone_core_create_proxy_config(lc); } else { isEditing = TRUE; @@ -381,30 +438,41 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); } char normalizedUserName[256]; - LinphoneAddress* linphoneAddress = linphone_address_new("sip:user@domain.com"); - linphone_proxy_config_normalize_number(proxyCfg, [username cStringUsingEncoding:[NSString defaultCStringEncoding]], normalizedUserName, sizeof(normalizedUserName)); + LinphoneAddress *linphoneAddress = linphone_address_new("sip:user@domain.com"); + linphone_proxy_config_normalize_number(proxyCfg, + [username cStringUsingEncoding:[NSString defaultCStringEncoding]], + normalizedUserName, sizeof(normalizedUserName)); linphone_address_set_username(linphoneAddress, normalizedUserName); linphone_address_set_domain(linphoneAddress, [domain cStringUsingEncoding:[NSString defaultCStringEncoding]]); - const char* identity = linphone_address_as_string_uri_only(linphoneAddress); - const char* password = [accountPassword cStringUsingEncoding:[NSString defaultCStringEncoding]]; - const char* ha1 = [accountHa1 cStringUsingEncoding:[NSString defaultCStringEncoding]]; + const char *identity = linphone_address_as_string_uri_only(linphoneAddress); + const char *password = [accountPassword cStringUsingEncoding:[NSString defaultCStringEncoding]]; + const char *ha1 = [accountHa1 cStringUsingEncoding:[NSString defaultCStringEncoding]]; + if (linphone_proxy_config_set_identity(proxyCfg, identity) == -1) { + error = NSLocalizedString(@"Invalid username or domain", nil); + goto bad_proxy; + } + if (linphone_proxy_config_set_server_addr(proxyCfg, proxy) == -1) { + error = NSLocalizedString(@"Invalid proxy address", nil); + goto bad_proxy; + } + if (linphone_proxy_config_set_route(proxyCfg, route) == -1) { + error = NSLocalizedString(@"Invalid route", nil); + goto bad_proxy; + } - if( linphone_proxy_config_set_identity(proxyCfg, identity) == -1 ) { error = NSLocalizedString(@"Invalid username or domain",nil); goto bad_proxy;} - if( linphone_proxy_config_set_server_addr(proxyCfg, proxy) == -1 ) { error = NSLocalizedString(@"Invalid proxy address", nil); goto bad_proxy; } - if( linphone_proxy_config_set_route(proxyCfg, route) == -1 ) { error = NSLocalizedString(@"Invalid route", nil); goto bad_proxy; } - - if ([prefix length]>0) { - linphone_proxy_config_set_dial_prefix(proxyCfg, [prefix cStringUsingEncoding:[NSString defaultCStringEncoding]]); + if ([prefix length] > 0) { + linphone_proxy_config_set_dial_prefix(proxyCfg, + [prefix cStringUsingEncoding:[NSString defaultCStringEncoding]]); } if ([self objectForKey:@"substitute_+_by_00_preference"]) { bool substitute_plus_by_00 = [self boolForKey:@"substitute_+_by_00_preference"]; - linphone_proxy_config_set_dial_escape_plus(proxyCfg,substitute_plus_by_00); + linphone_proxy_config_set_dial_escape_plus(proxyCfg, substitute_plus_by_00); } - lp_config_set_int(conf, LINPHONERC_APPLICATION_KEY, "pushnotification_preference", pushnotification); + [lm lpConfigSetInt:pushnotification forKey:@"pushnotification_preference"]; [[LinphoneManager instance] configurePushTokenForProxyConfig:proxyCfg]; linphone_proxy_config_enable_register(proxyCfg, true); @@ -413,9 +481,10 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); // setup auth info LinphoneAddress *from = linphone_address_new(identity); - if (from != 0){ - const char* userid_str = (userID != nil)? [userID UTF8String] : NULL; - info=linphone_auth_info_new(linphone_address_get_username(from),userid_str,password,ha1,NULL,linphone_proxy_config_get_domain(proxyCfg)); + if (from != 0) { + const char *userid_str = (userID != nil) ? [userID UTF8String] : NULL; + info = linphone_auth_info_new(linphone_address_get_username(from), userid_str, password, ha1, NULL, + linphone_proxy_config_get_domain(proxyCfg)); linphone_address_destroy(from); } @@ -423,178 +492,120 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); // add auth info linphone_core_clear_all_auth_info(lc); - if( info ) { linphone_core_add_auth_info(lc,info); } + if (info) { + linphone_core_add_auth_info(lc, info); + } // setup new proxycfg - if( isEditing ){ + if (isEditing) { linphone_proxy_config_done(proxyCfg); } else { // was a new proxy config, add it linphone_core_add_proxy_config(lc, proxyCfg); - linphone_core_set_default_proxy_config(lc,proxyCfg); + linphone_core_set_default_proxy_config(lc, proxyCfg); } bad_proxy: - if( linphoneAddress) + if (linphoneAddress) linphone_address_destroy(linphoneAddress); - if( proxy) + if (proxy) ms_free(proxy); - if( info ) + if (info) linphone_auth_info_destroy(info); // in case of error, show an alert to the user - if( error != nil ){ - if( isEditing ) linphone_proxy_config_done(proxyCfg); - else linphone_proxy_config_destroy(proxyCfg); + if (error != nil) { + if (isEditing) + linphone_proxy_config_done(proxyCfg); + else + linphone_proxy_config_destroy(proxyCfg); - [self alertAccountError:error]; + [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) + message:error + delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", nil) + otherButtonTitles:nil] show]; } } [[[LinphoneManager instance] fastAddressBook] reload]; } -+ (int)validPort:(int)port { - if(port < 0) { - return 0; - } - if(port > 65535) { - return 65535; - } - return port; -} - -+ (BOOL)parsePortRange:(NSString*)text minPort:(int*)minPort maxPort:(int*)maxPort { - NSError* error = nil; - *minPort = -1; - *maxPort = -1; - NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"([0-9]+)(([^0-9]+)([0-9]+))?" options:0 error:&error]; - if(error != NULL) - return FALSE; - NSArray* matches = [regex matchesInString:text options:0 range:NSMakeRange(0, [text length])]; - if([matches count] == 1) { - NSTextCheckingResult *match = [matches objectAtIndex:0]; - bool range = [match rangeAtIndex:2].length > 0; - if(!range) { - NSRange rangeMinPort = [match rangeAtIndex:1]; - *minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]]; - *maxPort = *minPort; - return TRUE; - } else { - NSRange rangeMinPort = [match rangeAtIndex:1]; - *minPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMinPort] intValue]]; - NSRange rangeMaxPort = [match rangeAtIndex:4]; - *maxPort = [LinphoneCoreSettingsStore validPort:[[text substringWithRange:rangeMaxPort] intValue]]; - if(*minPort > *maxPort) { - *minPort = *maxPort; - } - return TRUE; - } - } - return FALSE; -} - -- (BOOL)synchronize { - LinphoneCore *lc=[LinphoneManager getLc]; - - BOOL account_changed; - - account_changed=[self valueChangedForKey:@"username_preference"] - || [self valueChangedForKey:@"password_preference"] - || [self valueChangedForKey:@"domain_preference"] - || [self valueChangedForKey:@"expire_preference"] - || [self valueChangedForKey:@"proxy_preference"] - || [self valueChangedForKey:@"outbound_proxy_preference"] - || [self valueChangedForKey:@"transport_preference"] - || [self valueChangedForKey:@"port_preference"] - || [self valueChangedForKey:@"random_port_preference"] - || [self valueChangedForKey:@"prefix_preference"] - || [self valueChangedForKey:@"substitute_+_by_00_preference"] - || [self valueChangedForKey:@"use_ipv6"] - || [self valueChangedForKey:@"avpf_preference"] - || [self valueChangedForKey:@"pushnotification_preference"]; - - if (account_changed) - [self synchronizeAccount]; - - //Configure Codecs - +- (void)synchronizeCodecs:(const MSList *)codecs { + LinphoneCore *lc = [LinphoneManager getLc]; PayloadType *pt; const MSList *elem; - for (elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){ - pt=(PayloadType*)elem->data; - NSString *pref=[LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate]; - linphone_core_enable_payload_type(lc,pt,[self boolForKey: pref]); + for (elem = codecs; elem != NULL; elem = elem->next) { + pt = (PayloadType *)elem->data; + NSString *pref = [LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate]; + linphone_core_enable_payload_type(lc, pt, [self boolForKey:pref]); + } +} + +- (BOOL)synchronize { + LinphoneManager *lm = [LinphoneManager instance]; + LinphoneCore *lc = [LinphoneManager getLc]; + // root section + { + BOOL account_changed = + [self valueChangedForKey:@"username_preference"] || [self valueChangedForKey:@"password_preference"] || + [self valueChangedForKey:@"domain_preference"] || [self valueChangedForKey:@"expire_preference"] || + [self valueChangedForKey:@"proxy_preference"] || [self valueChangedForKey:@"outbound_proxy_preference"] || + [self valueChangedForKey:@"transport_preference"] || [self valueChangedForKey:@"port_preference"] || + [self valueChangedForKey:@"random_port_preference"] || [self valueChangedForKey:@"prefix_preference"] || + [self valueChangedForKey:@"substitute_+_by_00_preference"] || [self valueChangedForKey:@"use_ipv6"] || + [self valueChangedForKey:@"avpf_preference"] || [self valueChangedForKey:@"pushnotification_preference"]; + if (account_changed) + [self synchronizeAccount]; + + bool enableVideo = [self boolForKey:@"enable_video_preference"]; + linphone_core_enable_video(lc, enableVideo, enableVideo); } - for (elem=linphone_core_get_video_codecs(lc);elem!=NULL;elem=elem->next){ - pt=(PayloadType*)elem->data; - NSString *pref=[LinphoneManager getPreferenceForCodec:pt->mime_type withRate:pt->clock_rate]; - linphone_core_enable_payload_type(lc,pt,[self boolForKey: pref]); - } + // audio section + { + [self synchronizeCodecs:linphone_core_get_audio_codecs(lc)]; - LpConfig *config = linphone_core_get_config(lc); - lp_config_set_int(config, "audio", "codec_bitrate_limit", [self integerForKey:@"audio_codec_bitrate_limit_preference"]); - [[LinphoneManager instance] configureVbrCodecs]; - linphone_core_enable_adaptive_rate_control(lc, [self boolForKey:@"adaptive_rate_control_preference"]); - linphone_core_set_adaptive_rate_algorithm(lc, [ - [self stringForKey:@"adaptive_rate_algorithm_preference"] cStringUsingEncoding:[NSString defaultCStringEncoding] - ]); + float playback_gain = [self floatForKey:@"playback_gain_preference"]; + linphone_core_set_playback_gain_db(lc, playback_gain); - // Voice processing - BOOL voice_processing = [self boolForKey:@"voiceproc_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "voiceproc_preference", voice_processing); - NSString* au_device = @"AU: Audio Unit Receiver"; - if( !voice_processing ){ au_device = @"AU: Audio Unit NoVoiceProc"; } - linphone_core_set_capture_device(lc, [au_device UTF8String]); - linphone_core_set_playback_device(lc, [au_device UTF8String]); + float mic_gain = [self floatForKey:@"microphone_gain_preference"]; + linphone_core_set_mic_gain_db(lc, mic_gain); - BOOL equalizer = [self boolForKey:@"eq_active"]; - lp_config_set_int(config, "sound", "eq_active", equalizer); + [lm lpConfigSetInt:[self integerForKey:@"audio_codec_bitrate_limit_preference"] + forKey:@"codec_bitrate_limit" + forSection:@"audio"]; - linphone_core_set_use_info_for_dtmf(lc, [self boolForKey:@"sipinfo_dtmf_preference"]); - linphone_core_set_use_rfc2833_for_dtmf(lc, [self boolForKey:@"rfc_dtmf_preference"]); - linphone_core_set_inc_timeout(lc, [self integerForKey:@"incoming_call_timeout_preference"]); - linphone_core_set_in_call_timeout(lc, [self integerForKey:@"in_call_timeout_preference"]); - lp_config_set_string(config, "app", "voice_mail_uri", [[self stringForKey:@"voice_mail_uri_preference"] UTF8String]); + BOOL voice_processing = [self boolForKey:@"voiceproc_preference"]; + [lm lpConfigSetInt:voice_processing forKey:@"voiceproc_preference"]; - bool enableVideo = [self boolForKey:@"enable_video_preference"]; - linphone_core_enable_video(lc, enableVideo, enableVideo); + BOOL equalizer = [self boolForKey:@"eq_active"]; + [lm lpConfigSetBool:equalizer forKey:@"eq_active" forSection:@"sound"]; - NSString *menc = [self stringForKey:@"media_encryption_preference"]; - if (menc && [menc compare:@"SRTP"] == NSOrderedSame) - linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionSRTP); - else if (menc && [menc compare:@"ZRTP"] == NSOrderedSame) - linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionZRTP); - else if (menc && [menc compare:@"DTLS"] == NSOrderedSame) - linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionDTLS); - else - linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionNone); + [[LinphoneManager instance] configureVbrCodecs]; - NSString* stun_server = [self stringForKey:@"stun_preference"]; - if ([stun_server length] > 0){ - linphone_core_set_stun_server(lc, [stun_server UTF8String]); - BOOL ice_preference = [self boolForKey:@"ice_preference"]; - if(ice_preference) { - linphone_core_set_firewall_policy(lc, LinphonePolicyUseIce); - } else { - linphone_core_set_firewall_policy(lc, LinphonePolicyUseStun); + NSString *au_device = @"AU: Audio Unit Receiver"; + if (!voice_processing) { + au_device = @"AU: Audio Unit NoVoiceProc"; } - } else { - linphone_core_set_stun_server(lc, NULL); - linphone_core_set_firewall_policy(lc, LinphonePolicyNoFirewall); + linphone_core_set_capture_device(lc, [au_device UTF8String]); + linphone_core_set_playback_device(lc, [au_device UTF8String]); } - LinphoneVideoPolicy policy; - policy.automatically_accept = [self boolForKey:@"accept_video_preference"]; - policy.automatically_initiate = [self boolForKey:@"start_video_preference"]; - linphone_core_set_video_policy(lc, &policy); - linphone_core_enable_self_view(lc, [self boolForKey:@"self_video_preference"]); - BOOL preview_preference=[self boolForKey:@"preview_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "preview_preference", preview_preference); - MSVideoSize vsize; - int bw; - switch ([self integerForKey:@"video_preferred_size_preference"]) { + // video section + { + [self synchronizeCodecs:linphone_core_get_video_codecs(lc)]; + + LinphoneVideoPolicy policy; + policy.automatically_initiate = [self boolForKey:@"start_video_preference"]; + policy.automatically_accept = [self boolForKey:@"accept_video_preference"]; + linphone_core_set_video_policy(lc, &policy); + linphone_core_enable_self_view(lc, [self boolForKey:@"self_video_preference"]); + BOOL preview_preference = [self boolForKey:@"preview_preference"]; + [lm lpConfigSetInt:preview_preference forKey:@"preview_preference"]; + int bw; + MSVideoSize vsize; + switch ([self integerForKey:@"video_preferred_size_preference"]) { case 0: MS_VIDEO_SIZE_ASSIGN(vsize, 720P); // 128 = margin for audio, the BW includes both video and audio @@ -611,124 +622,152 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); MS_VIDEO_SIZE_ASSIGN(vsize, QVGA); bw = 380; break; - } - linphone_core_set_preferred_video_size(lc, vsize); - [self setInteger: bw forKey:@"upload_bandwidth_preference"]; - [self setInteger: bw forKey:@"download_bandwidth_preference"]; - - // Primary contact - NSString* displayname = [self stringForKey:@"primary_displayname_preference"]; - NSString* username = [self stringForKey:@"primary_username_preference"]; - LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc); - if(parsed != NULL) { - linphone_address_set_display_name(parsed,[displayname cStringUsingEncoding:[NSString defaultCStringEncoding]]); - linphone_address_set_username(parsed,[username cStringUsingEncoding:[NSString defaultCStringEncoding]]); - char *contact = linphone_address_as_string(parsed); - linphone_core_set_primary_contact(lc, contact); - ms_free(contact); - linphone_address_destroy(parsed); + } + [self setInteger:bw forKey:@"upload_bandwidth_preference"]; + [self setInteger:bw forKey:@"download_bandwidth_preference"]; + linphone_core_set_preferred_video_size(lc, vsize); } - - // Audio & Video Port + // call section { - NSString *audio_port_preference = [self stringForKey:@"audio_port_preference"]; - int minPort, maxPort; - [LinphoneCoreSettingsStore parsePortRange:audio_port_preference minPort:&minPort maxPort:&maxPort]; - linphone_core_set_audio_port_range(lc, minPort, maxPort); + linphone_core_set_use_rfc2833_for_dtmf(lc, [self boolForKey:@"rfc_dtmf_preference"]); + linphone_core_set_use_info_for_dtmf(lc, [self boolForKey:@"sipinfo_dtmf_preference"]); + linphone_core_set_inc_timeout(lc, [self integerForKey:@"incoming_call_timeout_preference"]); + linphone_core_set_in_call_timeout(lc, [self integerForKey:@"in_call_timeout_preference"]); + [[LinphoneManager instance] lpConfigSetString:[self stringForKey:@"voice_mail_uri_preference"] + forKey:@"voice_mail_uri"]; } + + // network section { - NSString *video_port_preference = [self stringForKey:@"video_port_preference"]; - int minPort, maxPort; - [LinphoneCoreSettingsStore parsePortRange:video_port_preference minPort:&minPort maxPort:&maxPort]; - linphone_core_set_video_port_range(lc, minPort, maxPort); - } + BOOL edgeOpt = [self boolForKey:@"edge_opt_preference"]; + [lm lpConfigSetInt:edgeOpt forKey:@"edge_opt_preference"]; - int upload_bandwidth = [self integerForKey:@"upload_bandwidth_preference"]; - linphone_core_set_upload_bandwidth(lc, upload_bandwidth); - - int download_bandwidth = [self integerForKey:@"download_bandwidth_preference"]; - linphone_core_set_download_bandwidth(lc, download_bandwidth); - - float playback_gain = [self floatForKey:@"playback_gain_preference"]; - linphone_core_set_playback_gain_db(lc, playback_gain); - - float mic_gain = [self floatForKey:@"microphone_gain_preference"]; - linphone_core_set_mic_gain_db(lc, mic_gain); - - UIDevice* device = [UIDevice currentDevice]; - bool backgroundSupported = false; - if ([device respondsToSelector:@selector(isMultitaskingSupported)]) - backgroundSupported = [device isMultitaskingSupported]; - BOOL isbackgroundModeEnabled; - if (backgroundSupported) { - isbackgroundModeEnabled = [self boolForKey:@"backgroundmode_preference"]; - } else { - isbackgroundModeEnabled = false; - } - - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "backgroundmode_preference", isbackgroundModeEnabled); - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "start_at_boot_preference", [self boolForKey:@"start_at_boot_preference"]); - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "autoanswer_notif_preference", [self boolForKey:@"autoanswer_notif_preference"]); - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "advanced_account_preference", [self boolForKey:@"advanced_account_preference"]); - - BOOL firstloginview = [self boolForKey:@"enable_first_login_view_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "enable_first_login_view_preference", firstloginview); - - BOOL edgeOpt = [self boolForKey:@"edge_opt_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "edge_opt_preference", edgeOpt); - - BOOL debugmode = [self boolForKey:@"debugenable_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "debugenable_preference", debugmode); - [[LinphoneManager instance] setLogsEnabled:debugmode]; - - BOOL animations = [self boolForKey:@"animations_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "animations_preference", animations); - - BOOL wifiOnly = [self boolForKey:@"wifi_only_preference"]; - lp_config_set_int(config, LINPHONERC_APPLICATION_KEY, "wifi_only_preference", wifiOnly); - if([self valueChangedForKey:@"wifi_only_preference"]) { - [[LinphoneManager instance] setupNetworkReachabilityCallback]; - } - - NSString* sharing_server = [self stringForKey:@"sharing_server_preference"]; - [[LinphoneManager instance] lpConfigSetString:sharing_server forKey:@"sharing_server_preference"]; - linphone_core_set_file_transfer_server(lc, [sharing_server UTF8String]); - - //Tunnel - if (linphone_core_tunnel_available()){ - NSString* lTunnelPrefMode = [self stringForKey:@"tunnel_mode_preference"]; - NSString* lTunnelPrefAddress = [self stringForKey:@"tunnel_address_preference"]; - int lTunnelPrefPort = [self integerForKey:@"tunnel_port_preference"]; - LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]); - TunnelMode mode = tunnel_off; - int lTunnelPort = 443; - if (lTunnelPrefPort) { - lTunnelPort = lTunnelPrefPort; + BOOL wifiOnly = [self boolForKey:@"wifi_only_preference"]; + [lm lpConfigSetInt:wifiOnly forKey:@"wifi_only_preference"]; + if ([self valueChangedForKey:@"wifi_only_preference"]) { + [[LinphoneManager instance] setupNetworkReachabilityCallback]; } - linphone_tunnel_clean_servers(tunnel); - if (lTunnelPrefAddress && [lTunnelPrefAddress length]) { - LinphoneTunnelConfig *ltc = linphone_tunnel_config_new(); - linphone_tunnel_config_set_host(ltc, [lTunnelPrefAddress UTF8String]); - linphone_tunnel_config_set_port(ltc, lTunnelPort); - linphone_tunnel_add_server(tunnel, ltc); - - if ([lTunnelPrefMode isEqualToString:@"off"]) { - mode = tunnel_off; - } else if ([lTunnelPrefMode isEqualToString:@"on"]) { - mode = tunnel_on; - } else if ([lTunnelPrefMode isEqualToString:@"wwan"]) { - mode = tunnel_wwan; - } else if ([lTunnelPrefMode isEqualToString:@"auto"]) { - mode = tunnel_auto; + NSString *stun_server = [self stringForKey:@"stun_preference"]; + if ([stun_server length] > 0) { + linphone_core_set_stun_server(lc, [stun_server UTF8String]); + BOOL ice_preference = [self boolForKey:@"ice_preference"]; + if (ice_preference) { + linphone_core_set_firewall_policy(lc, LinphonePolicyUseIce); } else { - LOGE(@"Unexpected tunnel mode [%s]",[lTunnelPrefMode cStringUsingEncoding:[NSString defaultCStringEncoding]]); + linphone_core_set_firewall_policy(lc, LinphonePolicyUseStun); } + } else { + linphone_core_set_stun_server(lc, NULL); + linphone_core_set_firewall_policy(lc, LinphonePolicyNoFirewall); } - lp_config_set_string(linphone_core_get_config(lc), LINPHONERC_APPLICATION_KEY, "tunnel_mode_preference", [lTunnelPrefMode UTF8String]); - [[LinphoneManager instance] setTunnelMode:mode]; + { + NSString *audio_port_preference = [self stringForKey:@"audio_port_preference"]; + int minPort, maxPort; + [LinphoneCoreSettingsStore parsePortRange:audio_port_preference minPort:&minPort maxPort:&maxPort]; + linphone_core_set_audio_port_range(lc, minPort, maxPort); + } + { + NSString *video_port_preference = [self stringForKey:@"video_port_preference"]; + int minPort, maxPort; + [LinphoneCoreSettingsStore parsePortRange:video_port_preference minPort:&minPort maxPort:&maxPort]; + linphone_core_set_video_port_range(lc, minPort, maxPort); + } + + NSString *menc = [self stringForKey:@"media_encryption_preference"]; + if (menc && [menc compare:@"SRTP"] == NSOrderedSame) + linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionSRTP); + else if (menc && [menc compare:@"ZRTP"] == NSOrderedSame) + linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionZRTP); + else if (menc && [menc compare:@"DTLS"] == NSOrderedSame) + linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionDTLS); + else + linphone_core_set_media_encryption(lc, LinphoneMediaEncryptionNone); + + linphone_core_enable_adaptive_rate_control(lc, [self boolForKey:@"adaptive_rate_control_preference"]); + linphone_core_set_adaptive_rate_algorithm(lc, [[self stringForKey:@"adaptive_rate_algorithm_preference"] + cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } + + // tunnel section + { + if (linphone_core_tunnel_available()) { + NSString *lTunnelPrefMode = [self stringForKey:@"tunnel_mode_preference"]; + NSString *lTunnelPrefAddress = [self stringForKey:@"tunnel_address_preference"]; + int lTunnelPrefPort = [self integerForKey:@"tunnel_port_preference"]; + LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]); + TunnelMode mode = tunnel_off; + int lTunnelPort = 443; + if (lTunnelPrefPort) { + lTunnelPort = lTunnelPrefPort; + } + + linphone_tunnel_clean_servers(tunnel); + if (lTunnelPrefAddress && [lTunnelPrefAddress length]) { + LinphoneTunnelConfig *ltc = linphone_tunnel_config_new(); + linphone_tunnel_config_set_host(ltc, [lTunnelPrefAddress UTF8String]); + linphone_tunnel_config_set_port(ltc, lTunnelPort); + linphone_tunnel_add_server(tunnel, ltc); + + if ([lTunnelPrefMode isEqualToString:@"off"]) { + mode = tunnel_off; + } else if ([lTunnelPrefMode isEqualToString:@"on"]) { + mode = tunnel_on; + } else if ([lTunnelPrefMode isEqualToString:@"wwan"]) { + mode = tunnel_wwan; + } else if ([lTunnelPrefMode isEqualToString:@"auto"]) { + mode = tunnel_auto; + } else { + LOGE(@"Unexpected tunnel mode [%s]", + [lTunnelPrefMode cStringUsingEncoding:[NSString defaultCStringEncoding]]); + } + } + + [lm lpConfigSetString:lTunnelPrefMode forKey:@"tunnel_mode_preference"]; + [[LinphoneManager instance] setTunnelMode:mode]; + } + } + + // advanced section + { + BOOL debugmode = [self boolForKey:@"debugenable_preference"]; + [lm lpConfigSetInt:debugmode forKey:@"debugenable_preference"]; + [[LinphoneManager instance] setLogsEnabled:debugmode]; + + BOOL animations = [self boolForKey:@"animations_preference"]; + [lm lpConfigSetInt:animations forKey:@"animations_preference"]; + + UIDevice *device = [UIDevice currentDevice]; + bool backgroundSupported = + [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]; + BOOL isbackgroundModeEnabled = backgroundSupported && [self boolForKey:@"backgroundmode_preference"]; + [lm lpConfigSetInt:isbackgroundModeEnabled forKey:@"backgroundmode_preference"]; + + [lm lpConfigSetInt:[self integerForKey:@"start_at_boot_preference"] forKey:@"start_at_boot_preference"]; + [lm lpConfigSetInt:[self integerForKey:@"autoanswer_notif_preference"] forKey:@"autoanswer_notif_preference"]; + + BOOL firstloginview = [self boolForKey:@"enable_first_login_view_preference"]; + [lm lpConfigSetInt:firstloginview forKey:@"enable_first_login_view_preference"]; + + NSString *displayname = [self stringForKey:@"primary_displayname_preference"]; + NSString *username = [self stringForKey:@"primary_username_preference"]; + LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed(lc); + if (parsed != NULL) { + linphone_address_set_display_name(parsed, + [displayname cStringUsingEncoding:[NSString defaultCStringEncoding]]); + linphone_address_set_username(parsed, [username cStringUsingEncoding:[NSString defaultCStringEncoding]]); + char *contact = linphone_address_as_string(parsed); + linphone_core_set_primary_contact(lc, contact); + ms_free(contact); + linphone_address_destroy(parsed); + } + + [lm lpConfigSetInt:[self integerForKey:@"advanced_account_preference"] forKey:@"advanced_account_preference"]; + + NSString *sharing_server = [self stringForKey:@"sharing_server_preference"]; + [[LinphoneManager instance] lpConfigSetString:sharing_server forKey:@"sharing_server_preference"]; } changedDict = [[NSMutableDictionary alloc] init]; diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 08f868929..5ad82797f 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -36,7 +36,7 @@ #include "linphone/linphonecore.h" #include "linphone/linphone_tunnel.h" -extern const char *const LINPHONERC_APPLICATION_KEY; +extern NSString *const LINPHONERC_APPLICATION_KEY; extern NSString *const kLinphoneCoreUpdate; extern NSString *const kLinphoneDisplayStatusUpdate; @@ -169,18 +169,26 @@ typedef struct _LinphoneManagerSounds { +(void)setValueInMessageAppData:(id)value forKey:(NSString*)key inMessage:(LinphoneChatMessage*)msg; - (void)lpConfigSetString:(NSString*)value forKey:(NSString*)key; -- (NSString*)lpConfigStringForKey:(NSString*)key; -- (NSString*)lpConfigStringForKey:(NSString*)key withDefault:(NSString*)value; - (void)lpConfigSetString:(NSString*)value forKey:(NSString*)key forSection:(NSString*)section; +- (NSString *)lpConfigStringForKey:(NSString *)key; - (NSString*)lpConfigStringForKey:(NSString*)key forSection:(NSString*)section; -- (void)lpConfigSetInt:(NSInteger)value forKey:(NSString*)key; -- (NSInteger)lpConfigIntForKey:(NSString*)key; -- (void)lpConfigSetInt:(NSInteger)value forKey:(NSString*)key forSection:(NSString*)section; -- (NSInteger)lpConfigIntForKey:(NSString*)key forSection:(NSString*)section; +- (NSString *)lpConfigStringForKey:(NSString *)key withDefault:(NSString *)value; +- (NSString *)lpConfigStringForKey:(NSString *)key forSection:(NSString *)section withDefault:(NSString *)value; + +- (void)lpConfigSetInt:(int)value forKey:(NSString *)key; +- (void)lpConfigSetInt:(int)value forKey:(NSString *)key forSection:(NSString *)section; +- (int)lpConfigIntForKey:(NSString *)key; +- (int)lpConfigIntForKey:(NSString *)key forSection:(NSString *)section; +- (int)lpConfigIntForKey:(NSString *)key withDefault:(int)value; +- (int)lpConfigIntForKey:(NSString *)key forSection:(NSString *)section withDefault:(int)value; + - (void)lpConfigSetBool:(BOOL)value forKey:(NSString*)key; -- (BOOL)lpConfigBoolForKey:(NSString*)key; - (void)lpConfigSetBool:(BOOL)value forKey:(NSString*)key forSection:(NSString*)section; +- (BOOL)lpConfigBoolForKey:(NSString *)key; - (BOOL)lpConfigBoolForKey:(NSString*)key forSection:(NSString*)section; +- (BOOL)lpConfigBoolForKey:(NSString *)key withDefault:(BOOL)value; +- (BOOL)lpConfigBoolForKey:(NSString *)key forSection:(NSString *)section withDefault:(BOOL)value; + - (void)silentPushFailed:(NSTimer*)timer; @property (readonly) BOOL isTesting; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index db9bc07f3..fd59f4de9 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -52,7 +52,7 @@ static void audioRouteChangeListenerCallback ( static LinphoneCore* theLinphoneCore = nil; static LinphoneManager* theLinphoneManager = nil; -const char *const LINPHONERC_APPLICATION_KEY = "app"; +NSString *const LINPHONERC_APPLICATION_KEY = @"app"; NSString *const kLinphoneCoreUpdate = @"LinphoneCoreUpdate"; NSString *const kLinphoneDisplayStatusUpdate = @"LinphoneDisplayStatusUpdate"; @@ -285,7 +285,7 @@ struct codec_name_pref_table codec_pref_table[]={ [self overrideDefaultSettings]; //set default values for first boot - if (lp_config_get_string(configDb,LINPHONERC_APPLICATION_KEY,"debugenable_preference",NULL)==NULL){ + if ([self lpConfigStringForKey:@"debugenable_preference"] == nil) { #ifdef DEBUG [self lpConfigSetBool:TRUE forKey:@"debugenable_preference"]; #else @@ -449,11 +449,11 @@ exit_dbmigration: } - (void)migrateFromUserPrefs { - static const char* migration_flag = "userpref_migration_done"; + static NSString *migration_flag = @"userpref_migration_done"; if( configDb == nil ) return; - if( lp_config_get_int(configDb, LINPHONERC_APPLICATION_KEY, migration_flag, 0) ){ + if ([self lpConfigIntForKey:migration_flag withDefault:0]) { LOGI(@"UserPrefs migration already performed, skip"); return; } @@ -470,12 +470,12 @@ exit_dbmigration: for( NSString* userpref in values ){ if( [defaults_keys containsObject:userpref] ){ LOGI(@"Migrating %@ from user preferences: %d", userpref, [[defaults objectForKey:userpref] boolValue]); - lp_config_set_int(configDb, LINPHONERC_APPLICATION_KEY, [userpref UTF8String], [[defaults objectForKey:userpref] boolValue]); + [self lpConfigSetBool:[[defaults objectForKey:userpref] boolValue] forKey:userpref]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:userpref]; shouldSync = TRUE; - } else if ( lp_config_get_string(configDb, LINPHONERC_APPLICATION_KEY, [userpref UTF8String], NULL) == NULL ){ + } else if ([self lpConfigStringForKey:userpref] == nil) { // no default value found in our linphonerc, we need to add them - lp_config_set_int(configDb, LINPHONERC_APPLICATION_KEY, [userpref UTF8String], [[values objectForKey:userpref] boolValue]); + [self lpConfigSetBool:[[values objectForKey:userpref] boolValue] forKey:userpref]; } } @@ -484,7 +484,7 @@ exit_dbmigration: [[NSUserDefaults standardUserDefaults] synchronize]; } // don't get back here in the future - lp_config_set_int(configDb, LINPHONERC_APPLICATION_KEY, migration_flag, 1); + [self lpConfigSetBool:YES forKey:migration_flag]; } @@ -1048,7 +1048,7 @@ static void networkReachabilityNotification(CFNotificationCenterRef center, void void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* nilCtx){ showNetworkFlags(flags); - LinphoneManager* lLinphoneMgr = [LinphoneManager instance]; + LinphoneManager *lm = [LinphoneManager instance]; SCNetworkReachabilityFlags networkDownFlags=kSCNetworkReachabilityFlagsConnectionRequired |kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand; if (theLinphoneCore != nil) { @@ -1058,30 +1058,28 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach struct NetworkReachabilityContext* ctx = nilCtx ? ((struct NetworkReachabilityContext*)nilCtx) : 0; if ((flags == 0) || (flags & networkDownFlags)) { linphone_core_set_network_reachable(theLinphoneCore, false); - lLinphoneMgr.connectivity = none; + lm.connectivity = none; [LinphoneManager kickOffNetworkConnection]; } else { LinphoneTunnel *tunnel = linphone_core_get_tunnel([LinphoneManager getLc]); Connectivity newConnectivity; - BOOL isWifiOnly = lp_config_get_int(lLinphoneMgr.configDb, LINPHONERC_APPLICATION_KEY, "wifi_only_preference",FALSE); + BOOL isWifiOnly = [lm lpConfigBoolForKey:@"wifi_only_preference" withDefault:FALSE]; if (!ctx || ctx->testWWan) newConnectivity = flags & kSCNetworkReachabilityFlagsIsWWAN ? wwan:wifi; else newConnectivity = wifi; - if (newConnectivity == wwan - && proxy - && isWifiOnly - && (lLinphoneMgr.connectivity == newConnectivity || lLinphoneMgr.connectivity == none)) { + if (newConnectivity == wwan && proxy && isWifiOnly && + (lm.connectivity == newConnectivity || lm.connectivity == none)) { linphone_proxy_config_expires(proxy, 0); } else if (proxy){ - NSInteger defaultExpire = [[LinphoneManager instance] lpConfigIntForKey:@"default_expires"]; + NSInteger defaultExpire = [lm lpConfigIntForKey:@"default_expires"]; if (defaultExpire>=0) linphone_proxy_config_expires(proxy, (int)defaultExpire); //else keep default value from linphonecore } - if (lLinphoneMgr.connectivity != newConnectivity) { + if (lm.connectivity != newConnectivity) { if (tunnel) linphone_tunnel_reconnect(tunnel); // connectivity has changed linphone_core_set_network_reachable(theLinphoneCore,false); @@ -1092,10 +1090,10 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach linphone_core_iterate(theLinphoneCore); LOGI(@"Network connectivity changed to type [%s]",(newConnectivity==wifi?"wifi":"wwan")); } - lLinphoneMgr.connectivity=newConnectivity; - switch (lLinphoneMgr.tunnelMode) { + lm.connectivity = newConnectivity; + switch (lm.tunnelMode) { case tunnel_wwan: - linphone_tunnel_enable(tunnel,lLinphoneMgr.connectivity == wwan); + linphone_tunnel_enable(tunnel, lm.connectivity == wwan); break; case tunnel_auto: linphone_tunnel_auto_detect(tunnel); @@ -1106,7 +1104,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach } } if (ctx && ctx->networkStateChanged) { - (*ctx->networkStateChanged)(lLinphoneMgr.connectivity); + (*ctx->networkStateChanged)(lm.connectivity); } } } @@ -2103,63 +2101,70 @@ static void audioRouteChangeListenerCallback ( #pragma mark - LPConfig Functions - (void)lpConfigSetString:(NSString*)value forKey:(NSString*)key { - [self lpConfigSetString:value forKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; + [self lpConfigSetString:value forKey:key forSection:LINPHONERC_APPLICATION_KEY]; } - - (void)lpConfigSetString:(NSString*)value forKey:(NSString*)key forSection:(NSString *)section { if (!key) return; lp_config_set_string(configDb, [section UTF8String], [key UTF8String], value?[value UTF8String]:NULL); } - - (NSString*)lpConfigStringForKey:(NSString*)key { - return [self lpConfigStringForKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; + return [self lpConfigStringForKey:key withDefault:nil]; } - (NSString*)lpConfigStringForKey:(NSString*)key withDefault:(NSString*)defaultValue { - NSString* value = [self lpConfigStringForKey:key]; - return value?value:defaultValue; + return [self lpConfigStringForKey:key forSection:LINPHONERC_APPLICATION_KEY withDefault:defaultValue]; } - - (NSString*)lpConfigStringForKey:(NSString*)key forSection:(NSString *)section { - if (!key) return nil; + return [self lpConfigStringForKey:key forSection:section withDefault:nil]; +} +- (NSString *)lpConfigStringForKey:(NSString *)key forSection:(NSString *)section withDefault:(NSString *)defaultValue { + if (!key) + return defaultValue; const char* value = lp_config_get_string(configDb, [section UTF8String], [key UTF8String], NULL); - if (value) - return [NSString stringWithUTF8String:value]; - else - return nil; + return value ? [NSString stringWithUTF8String:value] : defaultValue; } -- (void)lpConfigSetInt:(NSInteger)value forKey:(NSString*)key { - [self lpConfigSetInt:value forKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; +- (void)lpConfigSetInt:(int)value forKey:(NSString *)key { + [self lpConfigSetInt:value forKey:key forSection:LINPHONERC_APPLICATION_KEY]; } - -- (void)lpConfigSetInt:(NSInteger)value forKey:(NSString*)key forSection:(NSString *)section { +- (void)lpConfigSetInt:(int)value forKey:(NSString *)key forSection:(NSString *)section { if (!key) return; - lp_config_set_int(configDb, [section UTF8String], [key UTF8String], (int)value ); + lp_config_set_int(configDb, [section UTF8String], [key UTF8String], (int)value); } - -- (NSInteger)lpConfigIntForKey:(NSString*)key { - return [self lpConfigIntForKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; +- (int)lpConfigIntForKey:(NSString *)key { + return [self lpConfigIntForKey:key withDefault:-1]; } - -- (NSInteger)lpConfigIntForKey:(NSString*)key forSection:(NSString *)section { - if (!key) return -1; - return lp_config_get_int(configDb, [section UTF8String], [key UTF8String], -1); +- (int)lpConfigIntForKey:(NSString *)key withDefault:(int)defaultValue { + return [self lpConfigIntForKey:key forSection:LINPHONERC_APPLICATION_KEY withDefault:defaultValue]; +} +- (int)lpConfigIntForKey:(NSString *)key forSection:(NSString *)section { + return [self lpConfigIntForKey:key forSection:section withDefault:-1]; +} +- (int)lpConfigIntForKey:(NSString *)key forSection:(NSString *)section withDefault:(int)defaultValue { + if (!key) + return defaultValue; + return lp_config_get_int(configDb, [section UTF8String], [key UTF8String], (int)defaultValue); } - (void)lpConfigSetBool:(BOOL)value forKey:(NSString*)key { - [self lpConfigSetBool:value forKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; + [self lpConfigSetBool:value forKey:key forSection:LINPHONERC_APPLICATION_KEY]; } - - (void)lpConfigSetBool:(BOOL)value forKey:(NSString*)key forSection:(NSString *)section { - return [self lpConfigSetInt:(NSInteger)(value == TRUE) forKey:key forSection:section]; + [self lpConfigSetInt:(int)(value == TRUE)forKey:key forSection:section]; } - - (BOOL)lpConfigBoolForKey:(NSString*)key { - return [self lpConfigBoolForKey:key forSection:[NSString stringWithUTF8String:LINPHONERC_APPLICATION_KEY]]; + return [self lpConfigBoolForKey:key withDefault:FALSE]; +} +- (BOOL)lpConfigBoolForKey:(NSString *)key withDefault:(BOOL)defaultValue { + return [self lpConfigBoolForKey:key forSection:LINPHONERC_APPLICATION_KEY withDefault:defaultValue]; } - - (BOOL)lpConfigBoolForKey:(NSString*)key forSection:(NSString *)section { - return [self lpConfigIntForKey:key forSection:section] == 1; + return [self lpConfigBoolForKey:key forSection:section withDefault:FALSE]; +} +- (BOOL)lpConfigBoolForKey:(NSString *)key forSection:(NSString *)section withDefault:(BOOL)defaultValue { + if (!key) + return defaultValue; + int val = [self lpConfigIntForKey:key forSection:section withDefault:-1]; + return (val != -1) ? (val == 1) : defaultValue; } #pragma mark - GSM management diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index 9fab910a9..347c91582 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -605,8 +605,6 @@ static UICompositeViewDescription *compositeDescription = nil; [hiddenKeys addObject:@"microphone_gain_preference"]; [hiddenKeys addObject:@"network_limit_group"]; - [hiddenKeys addObject:@"upload_bandwidth_preference"]; - [hiddenKeys addObject:@"download_bandwidth_preference"]; [hiddenKeys addObject:@"incoming_call_timeout_preference"]; [hiddenKeys addObject:@"in_call_timeout_preference"]; diff --git a/Settings/InAppSettings.bundle/Audio.plist b/Settings/InAppSettings.bundle/Audio.plist index b9b3278f4..e61a70df2 100644 --- a/Settings/InAppSettings.bundle/Audio.plist +++ b/Settings/InAppSettings.bundle/Audio.plist @@ -218,36 +218,6 @@ IASKTextAlignment IASKUITextAlignmentRight - - DefaultValue - - Key - adaptive_rate_control_preference - Title - Adaptive rate control - Type - PSToggleSwitchSpecifier - - - DefaultValue - Simple - Key - adaptive_rate_algorithm_preference - Title - Adaptive rate algorithm - Titles - - Simple - Stateful - - Type - PSMultiValueSpecifier - Values - - Simple - Stateful - - DefaultValue 36 diff --git a/Settings/InAppSettings.bundle/Network.plist b/Settings/InAppSettings.bundle/Network.plist index 4eb893d65..e97766b92 100644 --- a/Settings/InAppSettings.bundle/Network.plist +++ b/Settings/InAppSettings.bundle/Network.plist @@ -156,31 +156,41 @@ Key - upload_bandwidth_preference + adaptive_rate_control_group Title - Upload bandwidth + Adaptive rate control Type - PSTextFieldSpecifier - KeyboardType - NumberPad - DefaultValue - 0 - IASKTextAlignment - IASKUITextAlignmentRight + PSGroupSpecifier - Key - download_bandwidth_preference - Title - Download bandwidth - Type - PSTextFieldSpecifier - KeyboardType - NumberPad DefaultValue - 0 - IASKTextAlignment - IASKUITextAlignmentRight + + Key + adaptive_rate_control_preference + Title + Adaptive rate control + Type + PSToggleSwitchSpecifier + + + DefaultValue + Simple + Key + adaptive_rate_algorithm_preference + Title + Adaptive rate algorithm + Titles + + Simple + Stateful + + Type + PSMultiValueSpecifier + Values + + Simple + Stateful + diff --git a/Settings/InAppSettings.bundle/Root.plist b/Settings/InAppSettings.bundle/Root.plist index 90c75b377..dedc25c2d 100644 --- a/Settings/InAppSettings.bundle/Root.plist +++ b/Settings/InAppSettings.bundle/Root.plist @@ -268,7 +268,7 @@ Key release_button Title - Exit + Release core Type IASKButtonSpecifier From 2d10de7d88f49bdc98181cda4c05950b9ee5ea92 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 16 Jun 2015 18:00:40 +0200 Subject: [PATCH 30/36] InAppSettingsVideo: add video preset, video FPS and bandwidth limit preferences --- Classes/LinphoneCoreSettingsStore.m | 14 +++- Classes/LinphoneUI/Base.lproj/UICallCell.xib | 25 ++++--- Classes/LinphoneUI/UICallCell.h | 8 +-- Classes/LinphoneUI/UICallCell.m | 42 ++++++------ Classes/SettingsViewController.m | 41 ++++++----- Settings/InAppSettings.bundle/Video.plist | 72 +++++++++++++++++++- submodules/linphone | 2 +- 7 files changed, 148 insertions(+), 56 deletions(-) diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 35ffcf31d..6db747a45 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -218,6 +218,9 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); [self setBool:linphone_core_self_view_enabled(lc) forKey:@"self_video_preference"]; BOOL previewEnabled = [lm lpConfigBoolForKey:@"preview_preference" withDefault:YES]; [self setBool:previewEnabled forKey:@"preview_preference"]; + + const char *preset = linphone_core_get_video_preset(lc); + [self setCString:preset ? preset : "default" forKey:@"video_preset_preference"]; MSVideoSize vsize = linphone_core_get_preferred_video_size(lc); int index; if ((vsize.width == MS_VIDEO_SIZE_720P_W) && (vsize.height == MS_VIDEO_SIZE_720P_H)) { @@ -228,6 +231,8 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); index = 2; } [self setInteger:index forKey:@"video_preferred_size_preference"]; + [self setInteger:linphone_core_get_preferred_framerate(lc) forKey:@"video_preferred_fps_preference"]; + [self setInteger:linphone_core_get_download_bandwidth(lc) forKey:@"download_bandwidth_preference"]; } // call section @@ -603,6 +608,8 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); linphone_core_enable_self_view(lc, [self boolForKey:@"self_video_preference"]); BOOL preview_preference = [self boolForKey:@"preview_preference"]; [lm lpConfigSetInt:preview_preference forKey:@"preview_preference"]; + + linphone_core_set_video_preset(lc, [[self stringForKey:@"video_preset_preference"] UTF8String]); int bw; MSVideoSize vsize; switch ([self integerForKey:@"video_preferred_size_preference"]) { @@ -623,9 +630,12 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); bw = 380; break; } - [self setInteger:bw forKey:@"upload_bandwidth_preference"]; - [self setInteger:bw forKey:@"download_bandwidth_preference"]; linphone_core_set_preferred_video_size(lc, vsize); + if (![[self stringForKey:@"video_preset_preference"] isEqualToString:@"custom"]) { + [self setInteger:bw forKey:@"download_bandwidth_preference"]; + } + linphone_core_set_preferred_framerate(lc, [self integerForKey:@"video_preferred_fps_preference"]); + linphone_core_set_download_bandwidth(lc, [self integerForKey:@"download_bandwidth_preference"]); } // call section diff --git a/Classes/LinphoneUI/Base.lproj/UICallCell.xib b/Classes/LinphoneUI/Base.lproj/UICallCell.xib index c46edde08..a4b4f72ce 100644 --- a/Classes/LinphoneUI/Base.lproj/UICallCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UICallCell.xib @@ -1,8 +1,7 @@ - + - - + @@ -33,10 +32,10 @@ - - - - + + + + @@ -218,11 +217,11 @@ - + - - + -