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..69a71bea9 --- /dev/null +++ b/.git-pre-commit @@ -0,0 +1,51 @@ +#!/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-status | grep -v '^D' | cut -f2) > 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 +} + +set -e +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. Skipping code verification..." + exit 0 +fi diff --git a/.gitignore b/.gitignore index 57e16863b..fc80e3d8f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ build test-reports WORK Makefile +OUTPUT +git-clang-format.diff 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 diff --git a/.travis.yml b/.travis.yml index a038e41b8..e5a5386ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,11 @@ xcode_sdk: iphonesimulator8.1 branches: only: - master - - travis_cmake env: global: - VERSION="8.1" - BYPASS_TOOLCHECK=1 - - KIF_SCREENSHOTS=Screens - secure: "JPPcWdmNIJiR3YcIwe0LRYce6qDdsiagO+eKKAp7eVk/wD9UHbz96Ms2FFkXxPhRJB1PA6Pf8FpAzIL2YRiJL9jRtKHSvtdF1cSto+57XyBkCsw7PkMVUIxp7fg6Wiwn3H3tucF8jisIkv/Pn7R+9EqePkZSqqu3+ig5AX9ApQ4=" before_install: @@ -29,11 +27,11 @@ before_install: - sudo ln -s /usr/bin/strings /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/strings - git submodule update --init --recursive -install: +install: - ./prepare.py all - - make + - make -s 1>/dev/null - mkdir -p Screens - export KIF_SCREENSHOTS=`pwd`/Screens after_script: - - ./Tools/imgur_upload.sh + - ./Tools/imgur_upload.sh 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 192ac77d6..f8e317dca 100644 --- a/Classes/ChatRoomTableViewController.h +++ b/Classes/ChatRoomTableViewController.h @@ -23,7 +23,6 @@ @protocol ChatRoomDelegate -- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo; - (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..425b06662 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 { @@ -183,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/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index f543f1868..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 53caf7475..fbcbc6ac9 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -21,10 +21,12 @@ #import "PhoneMainView.h" #import "DTActionSheet.h" #import "UILinphone.h" - +#import "DTAlertView.h" +#import "Utils/FileTransferDelegate.h" #import #import #import "Utils.h" +#import "UIChatRoomCell.h" @implementation ChatRoomViewController @@ -44,28 +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; - } - 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 { @@ -156,6 +153,7 @@ static UICompositeViewDescription *compositeDescription = nil; selector:@selector(textComposeEvent:) name:kLinphoneTextComposeEvent object:nil]; + if([tableController isEditing]) [tableController setEditing:FALSE animated:FALSE]; [editButton setOff]; @@ -167,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(imageSharing) { - [imageSharing cancel]; - } - [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 { @@ -211,7 +186,6 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - } -(void)didReceiveMemoryWarning { @@ -287,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]; } @@ -317,39 +291,34 @@ 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) { - LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]); + // 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]; - return; - } - LOGI(@"Image saved to [%@]", [assetURL absoluteString]); - [self chatRoomStartImageUpload:image url:assetURL]; - }); - }]; - }); - } else { - [self chatRoomStartImageUpload:image url:url]; - } + 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 { - [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]; @@ -365,7 +334,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]; }); }); @@ -498,8 +466,8 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark - Action Functions - (IBAction)onBackClick:(id)event { - [self.tableController setChatRoom:NULL]; - [[PhoneMainView instance] popCurrentView]; + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; } - (IBAction)onEditClick:(id)event { @@ -577,111 +545,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:(NSURL*)url userInfo:(id)userInfo { - if(imageSharing == nil) { - imageSharing = [ImageSharing newImageSharingDownload:url delegate:self userInfo:userInfo]; - [messageView setHidden:TRUE]; - [transferView setHidden:FALSE]; - return TRUE; - } - return FALSE; -} - - (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]; - [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)imageSharingProgress:(ImageSharing*)aimageSharing progress:(float)progress { - [imageTransferProgressBar setProgress:progress]; -} - -- (void)imageSharingAborted:(ImageSharing*)aimageSharing { - [messageView setHidden:FALSE]; - [transferView setHidden:TRUE]; - 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) { - LOGE(@"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]; - } else { - LOGE(@"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]; - } - 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) { - 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:chat]; - [tableController updateChatEntry:chat]; - }]; - imageSharing = nil; -} - - #pragma mark ImagePickerDelegate - (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info { @@ -698,7 +576,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [self chooseImageQuality:image url:url]; } - #pragma mark - Keyboard Event Functions - (void)keyboardWillHide:(NSNotification *)notif { diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index 23097283e..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" @@ -64,43 +66,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 { @@ -170,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/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index fd0d0c187..0872ae64f 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -369,7 +369,6 @@ static UICompositeViewDescription *compositeDescription = nil; char* lAddress = linphone_address_as_string_uri_only(addr); if(lAddress == NULL) return; - // 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/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 6fb88bfd0..000000000 --- a/Classes/ImageSharing.m +++ /dev/null @@ -1,177 +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/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/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 191972865..e392f1b9b 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,193 +36,191 @@ 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"]; + + 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)) { @@ -232,30 +231,112 @@ 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 { [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"]; [self setInteger:linphone_core_get_inc_timeout(lc) forKey:@"incoming_call_timeout_preference"]; [self setInteger:linphone_core_get_in_call_timeout(lc) forKey:@"in_call_timeout_preference"]; + + [self setBool:[lm lpConfigBoolForKey:@"repeat_call_notification"] + forKey:@"repeat_call_notification_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 +344,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 +378,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 +434,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 +446,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 +489,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 +500,123 @@ 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"]; + + NSString *videoPreset = [self stringForKey:@"video_preset_preference"]; + linphone_core_set_video_preset(lc, [videoPreset UTF8String]); + 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 @@ -604,131 +626,164 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args); MS_VIDEO_SIZE_ASSIGN(vsize, VGA); // no margin for VGA or QVGA, because video encoders can encode the // target resulution in less than the asked bandwidth - bw = 512; + bw = 660; break; case 2: default: 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); + } + linphone_core_set_preferred_video_size(lc, vsize); + if (![videoPreset isEqualToString:@"custom"]) { + [self setInteger:0 forKey:@"video_preferred_fps_preference"]; + [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"]); } - - // 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"]); + [lm lpConfigSetString:[self stringForKey:@"voice_mail_uri_preference"] forKey:@"voice_mail_uri"]; + [lm lpConfigSetBool:[self boolForKey:@"repeat_call_notification_preference"] + forKey:@"repeat_call_notification"]; } + + // 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"]; - - - //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 7daa5e605..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; @@ -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, @@ -167,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; @@ -203,5 +213,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 fb440ffb9..949bc6ec8 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"; @@ -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*/ @@ -145,10 +146,10 @@ struct codec_name_pref_table codec_pref_table[]={ { "mp4v-es", 90000, "mp4v-es_preference"}, { "h264", 90000, "h264_preference"}, { "vp8", 90000, "vp8_preference"}, - { "mpeg4-generic", 16000, "aaceld_16k_preference"}, - { "mpeg4-generic", 22050, "aaceld_22k_preference"}, - { "mpeg4-generic", 32000, "aaceld_32k_preference"}, - { "mpeg4-generic", 44100, "aaceld_44k_preference"}, + { "mpeg4-generic", 16000, "aaceld_16k_preference"}, + { "mpeg4-generic", 22050, "aaceld_22k_preference"}, + { "mpeg4-generic", 32000, "aaceld_32k_preference"}, + { "mpeg4-generic", 44100, "aaceld_44k_preference"}, { "mpeg4-generic", 48000, "aaceld_48k_preference"}, { "opus", 48000, "opus_preference"}, { NULL,0,Nil } @@ -194,9 +195,9 @@ struct codec_name_pref_table codec_pref_table[]={ } + (BOOL)isRunningTests { - NSDictionary *environment = [[NSProcessInfo processInfo] environment]; - NSString *injectBundle = environment[@"XCInjectBundle"]; - return [[injectBundle pathExtension] isEqualToString:@"xctest"]; + NSDictionary *environment = [[NSProcessInfo processInfo] environment]; + NSString *injectBundle = environment[@"XCInjectBundle"]; + return [[injectBundle pathExtension] isEqualToString:@"xctest"]; } + (BOOL)isNotIphone3G @@ -244,12 +245,12 @@ struct codec_name_pref_table codec_pref_table[]={ #endif + (BOOL)langageDirectionIsRTL { - static NSLocaleLanguageDirection dir = NSLocaleLanguageDirectionLeftToRight; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - dir = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; - }); - return dir == NSLocaleLanguageDirectionRightToLeft; + static NSLocaleLanguageDirection dir = NSLocaleLanguageDirectionLeftToRight; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dir = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; + }); + return dir == NSLocaleLanguageDirectionRightToLeft; } #pragma mark - Lifecycle Functions @@ -262,17 +263,18 @@ struct codec_name_pref_table codec_pref_table[]={ LOGE(@"cannot register route change handler [%ld]",lStatus); } - NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"]; - self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil]; + NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"]; + self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil]; - sounds.vibrate = kSystemSoundID_Vibrate; + sounds.vibrate = kSystemSoundID_Vibrate; - logs = [[NSMutableArray alloc] init]; + logs = [[NSMutableArray alloc] init]; database = NULL; speakerEnabled = FALSE; bluetoothEnabled = FALSE; tunnelMode = FALSE; + _fileTransferDelegates = [[NSMutableArray alloc] init]; pushCallIDs = [[NSMutableArray alloc] init ]; photoLibrary = [[ALAssetsLibrary alloc] init]; @@ -283,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 @@ -447,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; } @@ -468,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]; } } @@ -482,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]; } @@ -543,9 +545,9 @@ static void linphone_iphone_log(struct _LinphoneCore * lc, const char * message) - (void)displayStatus:(NSString*) message { // Post event - [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneDisplayStatusUpdate - object:self - userInfo:@{@"message":message}]; + [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneDisplayStatusUpdate + object:self + userInfo:@{@"message":message}]; } @@ -639,14 +641,15 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char data->notification = [[UILocalNotification alloc] init]; if (data->notification) { - // iOS8 doesn't need the timer trick for the local notification. - if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){ - data->notification.soundName = @"ring.caf"; - data->notification.category = @"incoming_call"; - } else { - data->notification.soundName = @"shortring.caf"; - data->timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(localNotifContinue:) userInfo:data->notification repeats:TRUE]; - } + // iOS8 doesn't need the timer trick for the local notification. + if ([[UIDevice currentDevice].systemVersion floatValue] >= 8 && + [self lpConfigBoolForKey:@"repeat_call_notification"] == NO) { + data->notification.soundName = @"ring.caf"; + data->notification.category = @"incoming_call"; + } else { + data->notification.soundName = @"shortring.caf"; + data->timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(localNotifContinue:) userInfo:data->notification repeats:TRUE]; + } data->notification.repeatInterval = 0; @@ -664,9 +667,9 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char incallBgTask=0; }]; - if( data->timer ){ - [[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes]; - } + if( data->timer ){ + [[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes]; + } } } @@ -740,9 +743,9 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char [self setupGSMInteraction]; } // Post event - NSDictionary* dict = @{@"call": [NSValue valueWithPointer:call], - @"state": [NSNumber numberWithInt:state], - @"message":[NSString stringWithUTF8String:message]}; + NSDictionary* dict = @{@"call": [NSValue valueWithPointer:call], + @"state": [NSNumber numberWithInt:state], + @"message":[NSString stringWithUTF8String:message]}; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneCallUpdate object:self userInfo:dict]; } @@ -845,12 +848,12 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo silentPushCompletion(UIBackgroundFetchResultNewData); silentPushCompletion = nil; } - const LinphoneAddress* remoteAddress = linphone_chat_message_get_from_address(msg); - char* c_address = linphone_address_as_string_uri_only(remoteAddress); - NSString* address = [NSString stringWithUTF8String:c_address]; - NSString* remote_uri = [NSString stringWithUTF8String:c_address]; - const char* call_id = linphone_chat_message_get_custom_header(msg, "Call-ID"); - NSString* callID = [NSString stringWithUTF8String:call_id]; + const LinphoneAddress* remoteAddress = linphone_chat_message_get_from_address(msg); + char* c_address = linphone_address_as_string_uri_only(remoteAddress); + NSString* address = [NSString stringWithUTF8String:c_address]; + NSString* remote_uri = [NSString stringWithUTF8String:c_address]; + const char* call_id = linphone_chat_message_get_custom_header(msg, "Call-ID"); + NSString* callID = [NSString stringWithUTF8String:call_id]; ms_free(c_address); @@ -874,9 +877,9 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo UILocalNotification* notif = [[UILocalNotification alloc] init]; if (notif) { notif.repeatInterval = 0; - if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){ - notif.category = @"incoming_msg"; - } + if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){ + notif.category = @"incoming_msg"; + } notif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"IM_MSG",nil), address]; notif.alertAction = NSLocalizedString(@"Show", nil); notif.soundName = @"msg.caf"; @@ -936,58 +939,58 @@ static void linphone_iphone_is_composing_received(LinphoneCore *lc, LinphoneChat } + (void)kickOffNetworkConnection { - static BOOL in_progress = FALSE; - if( in_progress ){ - LOGW(@"Connection kickoff already in progress"); - return; - } - in_progress = TRUE; + static BOOL in_progress = FALSE; + if( in_progress ){ + LOGW(@"Connection kickoff already in progress"); + return; + } + in_progress = TRUE; /* start a new thread to avoid blocking the main ui in case of peer host failure */ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - static int sleep_us = 10000; - static int timeout_s = 5; - BOOL timeout_reached = FALSE; - int loop = 0; + static int sleep_us = 10000; + static int timeout_s = 5; + BOOL timeout_reached = FALSE; + int loop = 0; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.0.200"/*"linphone.org"*/, 15000, nil, &writeStream); BOOL res = CFWriteStreamOpen (writeStream); const char* buff="hello"; - time_t start = time(NULL); - time_t loop_time; + time_t start = time(NULL); + time_t loop_time; - if( res == FALSE ){ - LOGI(@"Could not open write stream, backing off"); - CFRelease(writeStream); - in_progress = FALSE; - return; - } + if( res == FALSE ){ + LOGI(@"Could not open write stream, backing off"); + CFRelease(writeStream); + in_progress = FALSE; + return; + } - // check stream status and handle timeout - CFStreamStatus status = CFWriteStreamGetStatus(writeStream); - while (status != kCFStreamStatusOpen && status != kCFStreamStatusError ) { - usleep(sleep_us); - status = CFWriteStreamGetStatus(writeStream); - loop_time = time(NULL); - if( loop_time - start >= timeout_s){ - timeout_reached = TRUE; - break; - } - loop++; - } + // check stream status and handle timeout + CFStreamStatus status = CFWriteStreamGetStatus(writeStream); + while (status != kCFStreamStatusOpen && status != kCFStreamStatusError ) { + usleep(sleep_us); + status = CFWriteStreamGetStatus(writeStream); + loop_time = time(NULL); + if( loop_time - start >= timeout_s){ + timeout_reached = TRUE; + break; + } + loop++; + } - if (status == kCFStreamStatusOpen ) { - CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff)); - } else if( !timeout_reached ){ - CFErrorRef error = CFWriteStreamCopyError(writeStream); - LOGD(@"CFStreamError: %@", error); - CFRelease(error); - } else if( timeout_reached ){ - LOGI(@"CFStream timeout reached"); - } + if (status == kCFStreamStatusOpen ) { + CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff)); + } else if( !timeout_reached ){ + CFErrorRef error = CFWriteStreamCopyError(writeStream); + LOGD(@"CFStreamError: %@", error); + CFRelease(error); + } else if( timeout_reached ){ + LOGI(@"CFStream timeout reached"); + } CFWriteStreamClose (writeStream); CFRelease(writeStream); - in_progress = FALSE; + in_progress = FALSE; }); } @@ -1046,7 +1049,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) { @@ -1056,30 +1059,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); @@ -1090,10 +1091,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); @@ -1104,7 +1105,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach } } if (ctx && ctx->networkStateChanged) { - (*ctx->networkStateChanged)(lLinphoneMgr.connectivity); + (*ctx->networkStateChanged)(lm.connectivity); } } } @@ -1185,7 +1186,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach } } -#pragma mark - +#pragma mark - VTable static LinphoneCoreVTable linphonec_vtable = { .show =NULL, @@ -1208,6 +1209,8 @@ static LinphoneCoreVTable linphonec_vtable = { .notify_received = linphone_iphone_notify_received }; +#pragma mark - + //scheduling loop - (void)iterate { linphone_core_iterate(theLinphoneCore); @@ -1300,6 +1303,11 @@ static LinphoneCoreVTable linphonec_vtable = { linphone_core_set_static_picture(theLinphoneCore, imagePath); } + NSString *urlString = [self lpConfigStringForKey:@"sharing_server_preference"]; + if( urlString ){ + linphone_core_set_file_transfer_server(theLinphoneCore, [urlString UTF8String]); + } + /*DETECT cameras*/ frontCamId= backCamId=nil; char** camlist = (char**)linphone_core_get_video_devices(theLinphoneCore); @@ -1394,24 +1402,24 @@ static BOOL libStarted = FALSE; connectivity=none; - ms_init(); // Need to initialize mediastreamer2 before loading the plugins + ms_init(); // Need to initialize mediastreamer2 before loading the plugins - libmsilbc_init(); + libmsilbc_init(); #if defined (HAVE_SILK) - libmssilk_init(); + libmssilk_init(); #endif #ifdef HAVE_AMR - libmsamr_init(); //load amr plugin if present from the liblinphone sdk + libmsamr_init(); //load amr plugin if present from the liblinphone sdk #endif #ifdef HAVE_X264 - libmsx264_init(); //load x264 plugin if present from the liblinphone sdk + libmsx264_init(); //load x264 plugin if present from the liblinphone sdk #endif #ifdef HAVE_OPENH264 - libmsopenh264_init(); //load openh264 plugin if present from the liblinphone sdk + libmsopenh264_init(); //load openh264 plugin if present from the liblinphone sdk #endif #if HAVE_G729 - libmsbcg729_init(); // load g729 plugin + libmsbcg729_init(); // load g729 plugin #endif linphone_core_set_log_collection_path([[LinphoneManager cacheDirectory] UTF8String]); @@ -1490,39 +1498,39 @@ static int comp_call_id(const LinphoneCall* call , const char *callid) { } - (void)cancelLocalNotifTimerForCallId:(NSString*)callid { - //first, make sure this callid is not already involved in a call - MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); - MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]); - if (call != NULL) { - LinphoneCallAppData* data = (__bridge LinphoneCallAppData *)(linphone_call_get_user_data((LinphoneCall*)call->data)); - if ( data->timer ) - [data->timer invalidate]; - data->timer = nil; - return; - } + //first, make sure this callid is not already involved in a call + MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); + MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]); + if (call != NULL) { + LinphoneCallAppData* data = (__bridge LinphoneCallAppData *)(linphone_call_get_user_data((LinphoneCall*)call->data)); + if ( data->timer ) + [data->timer invalidate]; + data->timer = nil; + return; + } } - (void)acceptCallForCallId:(NSString*)callid { - //first, make sure this callid is not already involved in a call - MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); - MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]); - if (call != NULL) { - [self acceptCall:(LinphoneCall*)call->data]; - return; - }; + //first, make sure this callid is not already involved in a call + MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); + MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]); + if (call != NULL) { + [self acceptCall:(LinphoneCall*)call->data]; + return; + }; } - (void)addPushCallId:(NSString*) callid { //first, make sure this callid is not already involved in a call - MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); - if (ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String])) { - LOGW(@"Call id [%@] already handled",callid); - return; - }; - if ([pushCallIDs count] > 10 /*max number of pending notif*/) - [pushCallIDs removeObjectAtIndex:0]; + MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore); + if (ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String])) { + LOGW(@"Call id [%@] already handled",callid); + return; + }; + if ([pushCallIDs count] > 10 /*max number of pending notif*/) + [pushCallIDs removeObjectAtIndex:0]; - [pushCallIDs addObject:callid]; + [pushCallIDs addObject:callid]; } - (BOOL)popPushCallID:(NSString*) callId { @@ -1542,11 +1550,11 @@ static int comp_call_id(const LinphoneCall* call , const char *callid) { } - (void)playMessageSound { - BOOL success = [self.messagePlayer play]; - if( !success ){ - LOGE(@"Could not play the message sound"); - } - AudioServicesPlaySystemSound([LinphoneManager instance].sounds.vibrate); + BOOL success = [self.messagePlayer play]; + if( !success ){ + LOGE(@"Could not play the message sound"); + } + AudioServicesPlaySystemSound([LinphoneManager instance].sounds.vibrate); } static int comp_call_state_paused (const LinphoneCall* call, const void* param) { @@ -1559,7 +1567,7 @@ static int comp_call_state_paused (const LinphoneCall* call, const void* param) [[UIApplication sharedApplication] endBackgroundTask:pausedCallBgTask]; }]; LOGI(@"Long running task started, remaining [%g s] because at least one call is paused" - ,[[UIApplication sharedApplication] backgroundTimeRemaining]); + ,[[UIApplication sharedApplication] backgroundTimeRemaining]); } - (BOOL)enterBackgroundMode { LinphoneProxyConfig* proxyCfg; @@ -1864,18 +1872,18 @@ static void audioRouteChangeListenerCallback ( } LinphoneCall* call=NULL; - BOOL addressIsASCII = [address canBeConvertedToEncoding:[NSString defaultCStringEncoding]]; + BOOL addressIsASCII = [address canBeConvertedToEncoding:[NSString defaultCStringEncoding]]; if ([address length] == 0) return; //just return - if( !addressIsASCII ){ - UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address",nil) - message:NSLocalizedString(@"The address should only contain ASCII data",nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue",nil) - otherButtonTitles:nil]; - [error show]; + if( !addressIsASCII ){ + UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address",nil) + message:NSLocalizedString(@"The address should only contain ASCII data",nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Continue",nil) + otherButtonTitles:nil]; + [error show]; - } + } LinphoneAddress* linphoneAddress = linphone_core_interpret_url(theLinphoneCore, [address cStringUsingEncoding:[NSString defaultCStringEncoding]]); if (linphoneAddress) { @@ -1901,7 +1909,7 @@ static void audioRouteChangeListenerCallback ( otherButtonTitles:nil]; [error show]; - } + } if (call) { @@ -1929,16 +1937,16 @@ static void audioRouteChangeListenerCallback ( pushNotificationToken = nil; } - if(apushNotificationToken != nil) { - pushNotificationToken = apushNotificationToken; - } - LinphoneProxyConfig *cfg=nil; - linphone_core_get_default_proxy(theLinphoneCore, &cfg); - if (cfg ) { - linphone_proxy_config_edit(cfg); - [self configurePushTokenForProxyConfig: cfg]; - linphone_proxy_config_done(cfg); - } + if(apushNotificationToken != nil) { + pushNotificationToken = apushNotificationToken; + } + LinphoneProxyConfig *cfg=nil; + linphone_core_get_default_proxy(theLinphoneCore, &cfg); + if (cfg ) { + linphone_proxy_config_edit(cfg); + [self configurePushTokenForProxyConfig: cfg]; + linphone_proxy_config_done(cfg); + } } - (void)configurePushTokenForProxyConfig:(LinphoneProxyConfig*)proxyCfg{ @@ -1956,10 +1964,10 @@ static void audioRouteChangeListenerCallback ( #else #define APPMODE_SUFFIX @"prod" #endif - NSString *params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString]; + NSString *params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString]; - linphone_proxy_config_set_contact_uri_parameters(proxyCfg, [params UTF8String]); - linphone_proxy_config_set_contact_parameters(proxyCfg, NULL); + linphone_proxy_config_set_contact_uri_parameters(proxyCfg, [params UTF8String]); + linphone_proxy_config_set_contact_parameters(proxyCfg, NULL); } else { // no push token: linphone_proxy_config_set_contact_uri_parameters(proxyCfg, NULL); @@ -1990,22 +1998,22 @@ static void audioRouteChangeListenerCallback ( if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) { [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error]; } - return cachePath; + return cachePath; } + (int)unreadMessageCount { - int count = 0; - MSList* rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); - MSList* item = rooms; - while (item) { - LinphoneChatRoom* room = (LinphoneChatRoom*)item->data; - if( room ){ - count += linphone_chat_room_get_unread_messages_count(room); - } - item = item->next; - } + int count = 0; + MSList* rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); + MSList* item = rooms; + while (item) { + LinphoneChatRoom* room = (LinphoneChatRoom*)item->data; + if( room ){ + count += linphone_chat_room_get_unread_messages_count(room); + } + item = item->next; + } - return count; + return count; } + (BOOL)copyFile:(NSString*)src destination:(NSString*)dst override:(BOOL)override { @@ -2038,16 +2046,16 @@ static void audioRouteChangeListenerCallback ( - (void)configureVbrCodecs{ PayloadType *pt; int bitrate=lp_config_get_int(configDb,"audio","codec_bitrate_limit",kLinphoneAudioVbrCodecDefaultBitrate);/*default value is in linphonerc or linphonerc-factory*/ - const MSList *audio_codecs = linphone_core_get_audio_codecs(theLinphoneCore); - const MSList* codec = audio_codecs; - while (codec) { - pt = codec->data; - if( linphone_core_payload_type_is_vbr(theLinphoneCore, pt) ) { - linphone_core_set_payload_type_bitrate(theLinphoneCore, pt, bitrate); - } + const MSList *audio_codecs = linphone_core_get_audio_codecs(theLinphoneCore); + const MSList* codec = audio_codecs; + while (codec) { + pt = codec->data; + if( linphone_core_payload_type_is_vbr(theLinphoneCore, pt) ) { + linphone_core_set_payload_type_bitrate(theLinphoneCore, pt, bitrate); + } - codec = codec->next; - } + codec = codec->next; + } } -(void)setLogsEnabled:(BOOL)enabled { @@ -2094,63 +2102,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/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 @@ - + - - + - + + + + + + + @@ -121,4 +152,9 @@ - \ No newline at end of file + + + + + + diff --git a/Classes/LinphoneUI/UICallCell.h b/Classes/LinphoneUI/UICallCell.h index 71dbcb34d..43f4f13dd 100644 --- a/Classes/LinphoneUI/UICallCell.h +++ b/Classes/LinphoneUI/UICallCell.h @@ -78,10 +78,10 @@ typedef enum _UICallCellOtherView { @property (nonatomic, strong) IBOutlet UILabel* videoCodecLabel; @property (nonatomic, strong) IBOutlet UILabel* videoCodecHeaderLabel; -@property (strong, nonatomic) IBOutlet UILabel *videoSentSizeHeaderLabel; -@property (strong, nonatomic) IBOutlet UILabel *videoSentSizeLabel; -@property (strong, nonatomic) IBOutlet UILabel *videoRecvSizeHeaderLabel; -@property (strong, nonatomic) IBOutlet UILabel *videoRecvSizeLabel; +@property(strong, nonatomic) IBOutlet UILabel *videoSentSizeFPSHeaderLabel; +@property(strong, nonatomic) IBOutlet UILabel *videoSentSizeFPSLabel; +@property(strong, nonatomic) IBOutlet UILabel *videoRecvSizeFPSHeaderLabel; +@property(strong, nonatomic) IBOutlet UILabel *videoRecvSizeFPSLabel; @property (nonatomic, strong) IBOutlet UILabel* videoUploadBandwidthLabel; @property (nonatomic, strong) IBOutlet UILabel* videoUploadBandwidthHeaderLabel; diff --git a/Classes/LinphoneUI/UICallCell.m b/Classes/LinphoneUI/UICallCell.m index 90634f21d..4c9cfa5f2 100644 --- a/Classes/LinphoneUI/UICallCell.m +++ b/Classes/LinphoneUI/UICallCell.m @@ -120,8 +120,8 @@ @synthesize videoDownloadBandwidthLabel, videoDownloadBandwidthHeaderLabel; @synthesize videoIceConnectivityLabel, videoIceConnectivityHeaderLabel; -@synthesize videoRecvSizeHeaderLabel, videoRecvSizeLabel; -@synthesize videoSentSizeHeaderLabel, videoSentSizeLabel; +@synthesize videoRecvSizeFPSHeaderLabel, videoRecvSizeFPSLabel; +@synthesize videoSentSizeFPSHeaderLabel, videoSentSizeFPSLabel; @synthesize otherView; @@ -433,24 +433,28 @@ const LinphoneCallStats *stats = linphone_call_get_video_stats(call); - MSVideoSize sentSize = linphone_call_params_get_sent_video_size(params); - MSVideoSize recvSize = linphone_call_params_get_received_video_size(params); + if (stats != NULL && linphone_call_params_video_enabled(params)) { + MSVideoSize sentSize = linphone_call_params_get_sent_video_size(params); + MSVideoSize recvSize = linphone_call_params_get_received_video_size(params); + float sentFPS = linphone_call_params_get_sent_framerate(params); + float recvFPS = linphone_call_params_get_received_framerate(params); - if(stats != NULL) { - [videoUploadBandwidthLabel setText:[NSString stringWithFormat:@"%1.1f kbits/s", stats->upload_bandwidth]]; - [videoDownloadBandwidthLabel setText:[NSString stringWithFormat:@"%1.1f kbits/s", stats->download_bandwidth]]; - [videoIceConnectivityLabel setText:[UICallCell iceToString:stats->ice_state]]; - [videoSentSizeLabel setText:[NSString stringWithFormat:@"%dx%d",sentSize.width, sentSize.height]]; - [videoRecvSizeLabel setText:[NSString stringWithFormat:@"%dx%d",recvSize.width, recvSize.height]]; - } else { - [videoUploadBandwidthLabel setText:@""]; - [videoDownloadBandwidthLabel setText:@""]; - [videoIceConnectivityLabel setText:@""]; - [videoSentSizeLabel setText:@"0x0"]; - [videoRecvSizeLabel setText:@"0x0"]; - - } - } + [videoUploadBandwidthLabel setText:[NSString stringWithFormat:@"%1.1f kbits/s", stats->upload_bandwidth]]; + [videoDownloadBandwidthLabel + setText:[NSString stringWithFormat:@"%1.1f kbits/s", stats->download_bandwidth]]; + [videoIceConnectivityLabel setText:[UICallCell iceToString:stats->ice_state]]; + [videoSentSizeFPSLabel + setText:[NSString stringWithFormat:@"%dx%d (%.1fFPS)", sentSize.width, sentSize.height, sentFPS]]; + [videoRecvSizeFPSLabel + setText:[NSString stringWithFormat:@"%dx%d (%.1fFPS)", recvSize.width, recvSize.height, recvFPS]]; + } else { + [videoUploadBandwidthLabel setText:@""]; + [videoDownloadBandwidthLabel setText:@""]; + [videoIceConnectivityLabel setText:@""]; + [videoSentSizeFPSLabel setText:@"0x0"]; + [videoRecvSizeFPSLabel setText:@"0x0"]; + } + } } 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 45d02b40b..21d11c0c1 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,306 +58,418 @@ 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]; + [statusImage 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 { - NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(chat)]]; - [chatRoomDelegate chatRoomStartImageDownload:url userInfo:[NSValue valueWithPointer: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]; - } - } + 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 { - 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) { + 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]; + }); + } + } +} + +#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/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..2fd4cf558 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" @@ -46,88 +45,85 @@ @interface SettingsViewController (private) -+ (IASKSpecifier*)filterSpecifier:(IASKSpecifier *)specifier; ++ (IASKSpecifier *)filterSpecifier:(IASKSpecifier *)specifier; @end - #pragma mark - IASKSwitchEx Class @interface IASKSwitchEx : DCRoundSwitch { - NSString *_key; + NSString *_key; } -@property (nonatomic, strong) NSString *key; +@property(nonatomic, strong) NSString *key; @end @implementation IASKSwitchEx -@synthesize key=_key; +@synthesize key = _key; - (void)dealloc { - _key = nil; - + _key = nil; } @end - #pragma mark - IASKSpecifierValuesViewControllerEx Class // Patch IASKSpecifierValuesViewController -@interface IASKSpecifierValuesViewControllerEx: IASKSpecifierValuesViewController +@interface IASKSpecifierValuesViewControllerEx : IASKSpecifierValuesViewController @end @implementation IASKSpecifierValuesViewControllerEx - (void)initIASKSpecifierValuesViewControllerEx { - [self.view setBackgroundColor:[UIColor clearColor]]; + [self.view setBackgroundColor:[UIColor clearColor]]; } - (id)init { - self = [super init]; - if(self != nil) { - [self initIASKSpecifierValuesViewControllerEx]; - } - return self; + self = [super init]; + if (self != nil) { + [self initIASKSpecifierValuesViewControllerEx]; + } + return self; } - (id)initWithCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if(self != nil) { - [self initIASKSpecifierValuesViewControllerEx]; - } - return self; + self = [super initWithCoder:aDecoder]; + if (self != nil) { + [self initIASKSpecifierValuesViewControllerEx]; + } + return self; } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if(self != nil) { - [self initIASKSpecifierValuesViewControllerEx]; - } - return self; + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self != nil) { + [self initIASKSpecifierValuesViewControllerEx]; + } + return self; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell * cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; + UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; - // Background View - UACellBackgroundView *selectedBackgroundView = [[UACellBackgroundView alloc] initWithFrame:CGRectZero]; - cell.selectedBackgroundView = selectedBackgroundView; - [selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR]; - return cell; + // Background View + UACellBackgroundView *selectedBackgroundView = [[UACellBackgroundView alloc] initWithFrame:CGRectZero]; + cell.selectedBackgroundView = selectedBackgroundView; + [selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR]; + return cell; } @end - #pragma mark - IASKAppSettingsViewControllerEx Class -@interface IASKAppSettingsViewController(PrivateInterface) -- (UITableViewCell*)newCellForIdentifier:(NSString*)identifier; -@end; +@interface IASKAppSettingsViewController (PrivateInterface) +- (UITableViewCell *)newCellForIdentifier:(NSString *)identifier; +@end +; @interface IASKAppSettingsViewControllerEx : IASKAppSettingsViewController @@ -135,197 +131,200 @@ @implementation IASKAppSettingsViewControllerEx -- (UITableViewCell*)newCellForIdentifier:(NSString*)identifier { +- (UITableViewCell *)newCellForIdentifier:(NSString *)identifier { UITableViewCell *cell = nil; if ([identifier isEqualToString:kIASKPSToggleSwitchSpecifier]) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kIASKPSToggleSwitchSpecifier]; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault + reuseIdentifier:kIASKPSToggleSwitchSpecifier]; cell.accessoryView = [[IASKSwitchEx alloc] initWithFrame:CGRectMake(0, 0, 79, 27)]; - [((IASKSwitchEx*)cell.accessoryView) addTarget:self action:@selector(toggledValue:) forControlEvents:UIControlEventValueChanged]; - [((IASKSwitchEx*)cell.accessoryView) setOnTintColor:LINPHONE_MAIN_COLOR]; + [((IASKSwitchEx *)cell.accessoryView)addTarget:self + action:@selector(toggledValue:) + forControlEvents:UIControlEventValueChanged]; + [((IASKSwitchEx *)cell.accessoryView)setOnTintColor:LINPHONE_MAIN_COLOR]; cell.selectionStyle = UITableViewCellSelectionStyleNone; - cell.textLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont systemFontSize]; - cell.detailTextLabel.minimumScaleFactor = kIASKMinimumFontSize/[UIFont systemFontSize]; + cell.textLabel.minimumScaleFactor = kIASKMinimumFontSize / [UIFont systemFontSize]; + cell.detailTextLabel.minimumScaleFactor = kIASKMinimumFontSize / [UIFont systemFontSize]; } else { - cell = [super newCellForIdentifier:identifier]; - } - return cell; + cell = [super newCellForIdentifier:identifier]; + } + return cell; } - (void)toggledValue:(id)sender { - IASKSwitchEx *toggle = (IASKSwitchEx*)sender; - IASKSpecifier *spec = [_settingsReader specifierForKey:[toggle key]]; + IASKSwitchEx *toggle = (IASKSwitchEx *)sender; + IASKSpecifier *spec = [_settingsReader specifierForKey:[toggle key]]; - if ([toggle isOn]) { - if ([spec trueValue] != nil) { - [self.settingsStore setObject:[spec trueValue] forKey:[toggle key]]; - } - else { - [self.settingsStore setBool:YES forKey:[toggle key]]; - } - } - else { - if ([spec falseValue] != nil) { - [self.settingsStore setObject:[spec falseValue] forKey:[toggle key]]; - } - else { - [self.settingsStore setBool:NO forKey:[toggle key]]; - } - } - // Start notification after animation of DCRoundSwitch - dispatch_async(dispatch_get_main_queue(), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kIASKAppSettingChanged - object:[toggle key] - userInfo:[NSDictionary dictionaryWithObject:[self.settingsStore objectForKey:[toggle key]] - forKey:[toggle key]]]; - }); + if ([toggle isOn]) { + if ([spec trueValue] != nil) { + [self.settingsStore setObject:[spec trueValue] forKey:[toggle key]]; + } else { + [self.settingsStore setBool:YES forKey:[toggle key]]; + } + } else { + if ([spec falseValue] != nil) { + [self.settingsStore setObject:[spec falseValue] forKey:[toggle key]]; + } else { + [self.settingsStore setBool:NO forKey:[toggle key]]; + } + } + // Start notification after animation of DCRoundSwitch + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] + postNotificationName:kIASKAppSettingChanged + object:[toggle key] + userInfo:[NSDictionary dictionaryWithObject:[self.settingsStore objectForKey:[toggle key]] + forKey:[toggle key]]]; + }); } - (void)initIASKAppSettingsViewControllerEx { - [self.view setBackgroundColor:[UIColor clearColor]]; + [self.view setBackgroundColor:[UIColor clearColor]]; - // Force kIASKSpecifierValuesViewControllerIndex - static int kIASKSpecifierValuesViewControllerIndex = 0; - _viewList = [[NSMutableArray alloc] init]; - [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKSpecifierValuesView", @"ViewName",nil]]; - [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKAppSettingsView", @"ViewName",nil]]; + // Force kIASKSpecifierValuesViewControllerIndex + static int kIASKSpecifierValuesViewControllerIndex = 0; + _viewList = [[NSMutableArray alloc] init]; + [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKSpecifierValuesView", @"ViewName", nil]]; + [_viewList addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"IASKAppSettingsView", @"ViewName", nil]]; - NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3]; - [newItemDict addEntriesFromDictionary: [_viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex]]; // copy the title and explain strings + NSMutableDictionary *newItemDict = [NSMutableDictionary dictionaryWithCapacity:3]; + [newItemDict addEntriesFromDictionary:[_viewList objectAtIndex:kIASKSpecifierValuesViewControllerIndex]]; // copy + // the + // title + // and + // explain + // strings - IASKSpecifierValuesViewController *targetViewController = [[IASKSpecifierValuesViewControllerEx alloc] init]; - // add the new view controller to the dictionary and then to the 'viewList' array - [newItemDict setObject:targetViewController forKey:@"viewController"]; - [_viewList replaceObjectAtIndex:kIASKSpecifierValuesViewControllerIndex withObject:newItemDict]; + IASKSpecifierValuesViewController *targetViewController = [[IASKSpecifierValuesViewControllerEx alloc] init]; + // add the new view controller to the dictionary and then to the 'viewList' array + [newItemDict setObject:targetViewController forKey:@"viewController"]; + [_viewList replaceObjectAtIndex:kIASKSpecifierValuesViewControllerIndex withObject:newItemDict]; } -- (IASKSettingsReader*)settingsReader { - IASKSettingsReader *r = [super settingsReader]; - NSMutableArray *dataSource = [NSMutableArray arrayWithArray:[r dataSource]]; - for (int i = 0; i < [dataSource count]; ++i) { - NSMutableArray *specifiers = [NSMutableArray arrayWithArray:[dataSource objectAtIndex:i]]; - for (int j = 0; j < [specifiers count]; ++j) { - id sp = [specifiers objectAtIndex:j]; - if ([sp isKindOfClass:[IASKSpecifier class]]) { - sp = [SettingsViewController filterSpecifier:sp]; - } - [specifiers replaceObjectAtIndex:j withObject:sp]; - } +- (IASKSettingsReader *)settingsReader { + IASKSettingsReader *r = [super settingsReader]; + NSMutableArray *dataSource = [NSMutableArray arrayWithArray:[r dataSource]]; + for (int i = 0; i < [dataSource count]; ++i) { + NSMutableArray *specifiers = [NSMutableArray arrayWithArray:[dataSource objectAtIndex:i]]; + for (int j = 0; j < [specifiers count]; ++j) { + id sp = [specifiers objectAtIndex:j]; + if ([sp isKindOfClass:[IASKSpecifier class]]) { + sp = [SettingsViewController filterSpecifier:sp]; + } + [specifiers replaceObjectAtIndex:j withObject:sp]; + } - [dataSource replaceObjectAtIndex:i withObject:specifiers]; - } - [r setDataSource:dataSource]; - return r; + [dataSource replaceObjectAtIndex:i withObject:specifiers]; + } + [r setDataSource:dataSource]; + return r; } - (void)viewDidLoad { - [super viewDidLoad]; + [super viewDidLoad]; - - [self.tableView setBackgroundColor:[UIColor clearColor]]; // Can't do it in Xib: issue with ios4 - [self.tableView setBackgroundView:nil]; // Can't do it in Xib: issue with ios4 + [self.tableView setBackgroundColor:[UIColor clearColor]]; // Can't do it in Xib: issue with ios4 + [self.tableView setBackgroundView:nil]; // Can't do it in Xib: issue with ios4 } - (id)initWithStyle:(UITableViewStyle)style { - self = [super initWithStyle:style]; - if(self != nil) { - [self initIASKAppSettingsViewControllerEx]; - } - return self; + self = [super initWithStyle:style]; + if (self != nil) { + [self initIASKAppSettingsViewControllerEx]; + } + return self; } - (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; + [super viewWillAppear:animated]; - - UIEdgeInsets inset = {0, 0, 10, 0}; - UIScrollView *scrollView = self.tableView; - [scrollView setContentInset:inset]; - [scrollView setScrollIndicatorInsets:inset]; + UIEdgeInsets inset = {0, 0, 10, 0}; + UIScrollView *scrollView = self.tableView; + [scrollView setContentInset:inset]; + [scrollView setScrollIndicatorInsets:inset]; } - (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; + [super viewDidAppear:animated]; - UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"About", nil) style:UIBarButtonItemStyleBordered target:self action:@selector(onAboutClick:)]; - self.navigationItem.rightBarButtonItem = buttonItem; + UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"About", nil) + style:UIBarButtonItemStyleBordered + target:self + action:@selector(onAboutClick:)]; + self.navigationItem.rightBarButtonItem = buttonItem; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell * cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; + UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; - if([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]]) { - UITextField *field = ((IASKPSTextFieldSpecifierViewCell*)cell).textField; - [field setTextColor:LINPHONE_MAIN_COLOR]; - } + if ([cell isKindOfClass:[IASKPSTextFieldSpecifierViewCell class]]) { + UITextField *field = ((IASKPSTextFieldSpecifierViewCell *)cell).textField; + [field setTextColor:LINPHONE_MAIN_COLOR]; + } - if([cell isKindOfClass:[IASKPSTitleValueSpecifierViewCell class]]) { - cell.detailTextLabel.textColor = [UIColor grayColor]; - } else { - cell.detailTextLabel.textColor = LINPHONE_MAIN_COLOR; - } + if ([cell isKindOfClass:[IASKPSTitleValueSpecifierViewCell class]]) { + cell.detailTextLabel.textColor = [UIColor grayColor]; + } else { + cell.detailTextLabel.textColor = LINPHONE_MAIN_COLOR; + } - // Background View - UACellBackgroundView *selectedBackgroundView = [[UACellBackgroundView alloc] initWithFrame:CGRectZero]; - cell.selectedBackgroundView = selectedBackgroundView; - [selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR]; - return cell; + // Background View + UACellBackgroundView *selectedBackgroundView = [[UACellBackgroundView alloc] initWithFrame:CGRectZero]; + cell.selectedBackgroundView = selectedBackgroundView; + [selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR]; + return cell; } -- (IBAction)onAboutClick: (id)sender { - [[PhoneMainView instance] changeCurrentView:[AboutViewController compositeViewDescription] push:TRUE]; +- (IBAction)onAboutClick:(id)sender { + [[PhoneMainView instance] changeCurrentView:[AboutViewController compositeViewDescription] push:TRUE]; } @end - #pragma mark - UINavigationBarEx Class -@interface UINavigationBarEx: UINavigationBar { - +@interface UINavigationBarEx : UINavigationBar { } @end @implementation UINavigationBarEx - #pragma mark - Lifecycle Functions - (void)initUINavigationBarEx { - [self setTintColor:[LINPHONE_MAIN_COLOR adjustHue:5.0f/180.0f saturation:0.0f brightness:0.0f alpha:0.0f]]; + [self setTintColor:[LINPHONE_MAIN_COLOR adjustHue:5.0f / 180.0f saturation:0.0f brightness:0.0f alpha:0.0f]]; } - (id)init { - self = [super init]; - if (self) { - [self initUINavigationBarEx]; - } - return self; + self = [super init]; + if (self) { + [self initUINavigationBarEx]; + } + return self; } - (id)initWithCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if (self) { - [self initUINavigationBarEx]; - } - return self; + self = [super initWithCoder:aDecoder]; + if (self) { + [self initUINavigationBarEx]; + } + return self; } - (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - [self initUINavigationBarEx]; - } - return self; + self = [super initWithFrame:frame]; + if (self) { + [self initUINavigationBarEx]; + } + return self; } - (void)drawRect:(CGRect)rect { - UIImage *img = [UIImage imageNamed:@"toolsbar_background.png"]; - [img drawInRect:rect]; + UIImage *img = [UIImage imageNamed:@"toolsbar_background.png"]; + [img drawInRect:rect]; } @end - #pragma mark - UINavigationControllerEx Class @interface UINavigationControllerEx : UINavigationController @@ -335,53 +334,52 @@ @implementation UINavigationControllerEx - (id)initWithRootViewController:(UIViewController *)rootViewController { - [UINavigationControllerEx removeBackground:rootViewController.view]; - return [self initWithRootViewController:rootViewController]; + [UINavigationControllerEx removeBackground:rootViewController.view]; + return [self initWithRootViewController:rootViewController]; } -+ (void)removeBackground:(UIView*)view { - // iOS7 transparent background is *really* transparent: with an alpha != 0 - // it messes up the transitions. Use non-transparent BG for iOS7 - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) - [view setBackgroundColor:LINPHONE_SETTINGS_BG_IOS7]; - else - [view setBackgroundColor:[UIColor clearColor]]; ++ (void)removeBackground:(UIView *)view { + // iOS7 transparent background is *really* transparent: with an alpha != 0 + // it messes up the transitions. Use non-transparent BG for iOS7 + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) + [view setBackgroundColor:LINPHONE_SETTINGS_BG_IOS7]; + else + [view setBackgroundColor:[UIColor clearColor]]; } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { - [UINavigationControllerEx removeBackground:viewController.view]; + [UINavigationControllerEx removeBackground:viewController.view]; - [viewController viewWillAppear:animated]; // Force view - UILabel *labelTitleView = [[UILabel alloc] init]; - labelTitleView.backgroundColor = [UIColor clearColor]; - labelTitleView.textColor = [UIColor colorWithRed:0x41/255.0f green:0x48/255.0f blue:0x4f/255.0f alpha:1.0]; - labelTitleView.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.5]; - labelTitleView.font = [UIFont boldSystemFontOfSize:20]; - labelTitleView.shadowOffset = CGSizeMake(0,1); - labelTitleView.textAlignment = NSTextAlignmentCenter; - labelTitleView.text = viewController.title; - [labelTitleView sizeToFit]; - viewController.navigationItem.titleView = labelTitleView; - [super pushViewController:viewController animated:animated]; + [viewController viewWillAppear:animated]; // Force view + UILabel *labelTitleView = [[UILabel alloc] init]; + labelTitleView.backgroundColor = [UIColor clearColor]; + labelTitleView.textColor = [UIColor colorWithRed:0x41 / 255.0f green:0x48 / 255.0f blue:0x4f / 255.0f alpha:1.0]; + labelTitleView.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.5]; + labelTitleView.font = [UIFont boldSystemFontOfSize:20]; + labelTitleView.shadowOffset = CGSizeMake(0, 1); + labelTitleView.textAlignment = NSTextAlignmentCenter; + labelTitleView.text = viewController.title; + [labelTitleView sizeToFit]; + viewController.navigationItem.titleView = labelTitleView; + [super pushViewController:viewController animated:animated]; } - (void)setViewControllers:(NSArray *)viewControllers { - for(UIViewController *controller in viewControllers) { - [UINavigationControllerEx removeBackground:controller.view]; - } - [super setViewControllers:viewControllers]; + for (UIViewController *controller in viewControllers) { + [UINavigationControllerEx removeBackground:controller.view]; + } + [super setViewControllers:viewControllers]; } - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated { - for(UIViewController *controller in viewControllers) { - [UINavigationControllerEx removeBackground:controller.view]; - } - [super setViewControllers:viewControllers animated:animated]; + for (UIViewController *controller in viewControllers) { + [UINavigationControllerEx removeBackground:controller.view]; + } + [super setViewControllers:viewControllers animated:animated]; } @end - @implementation SettingsViewController @synthesize settingsController; @@ -390,13 +388,12 @@ #pragma mark - Lifecycle Functions - (id)init { - return [super initWithNibName:@"SettingsViewController" bundle:[NSBundle mainBundle]]; + return [super initWithNibName:@"SettingsViewController" bundle:[NSBundle mainBundle]]; } - - (void)dealloc { - // Remove all observer - [[NSNotificationCenter defaultCenter] removeObserver:self]; + // Remove all observer + [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - UICompositeViewDelegate Functions @@ -404,161 +401,161 @@ static UICompositeViewDescription *compositeDescription = nil; + (UICompositeViewDescription *)compositeViewDescription { - if(compositeDescription == nil) { - compositeDescription = [[UICompositeViewDescription alloc] init:@"Settings" - content:@"SettingsViewController" - stateBar:nil - stateBarEnabled:false - tabBar: @"UIMainBar" - tabBarEnabled:true - fullscreen:false - landscapeMode:[LinphoneManager runningOnIpad] - portraitMode:true]; - } - return compositeDescription; + if (compositeDescription == nil) { + compositeDescription = [[UICompositeViewDescription alloc] init:@"Settings" + content:@"SettingsViewController" + stateBar:nil + stateBarEnabled:false + tabBar:@"UIMainBar" + tabBarEnabled:true + fullscreen:false + landscapeMode:[LinphoneManager runningOnIpad] + portraitMode:true]; + } + return compositeDescription; } - #pragma mark - ViewController Functions - (void)viewDidLoad { - [super viewDidLoad]; + [super viewDidLoad]; settingsStore = [[LinphoneCoreSettingsStore alloc] init]; - settingsController.showDoneButton = FALSE; - settingsController.delegate = self; - settingsController.showCreditsFooter = FALSE; - settingsController.settingsStore = settingsStore; + settingsController.showDoneButton = FALSE; + settingsController.delegate = self; + settingsController.showCreditsFooter = FALSE; + settingsController.settingsStore = settingsStore; - [navigationController.view setBackgroundColor:[UIColor clearColor]]; + [navigationController.view setBackgroundColor:[UIColor clearColor]]; - navigationController.view.frame = self.view.frame; - [navigationController pushViewController:settingsController animated:FALSE]; - [self.view addSubview: navigationController.view]; + navigationController.view.frame = self.view.frame; + [navigationController pushViewController:settingsController animated:FALSE]; + [self.view addSubview:navigationController.view]; } - (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [settingsController dismiss:self]; - // Set observer - [[NSNotificationCenter defaultCenter] removeObserver:self - name:kIASKAppSettingChanged - object:nil]; + [super viewWillDisappear:animated]; + [settingsController dismiss:self]; + // Set observer + [[NSNotificationCenter defaultCenter] removeObserver:self name:kIASKAppSettingChanged object:nil]; } - (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; + [super viewWillAppear:animated]; - [settingsStore transformLinphoneCoreToKeys]; // Sync settings with linphone core settings - settingsController.hiddenKeys = [self findHiddenKeys]; - [settingsController.tableView reloadData]; - - // Set observer - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(appSettingChanged:) - name:kIASKAppSettingChanged - object:nil]; + [settingsStore transformLinphoneCoreToKeys]; // Sync settings with linphone core settings + settingsController.hiddenKeys = [self findHiddenKeys]; + [settingsController.tableView reloadData]; + // Set observer + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appSettingChanged:) + name:kIASKAppSettingChanged + object:nil]; } - #pragma mark - Event Functions -- (void)appSettingChanged:(NSNotification*) notif { +- (void)appSettingChanged:(NSNotification *)notif { NSMutableSet *hiddenKeys = [NSMutableSet setWithSet:[settingsController hiddenKeys]]; - NSMutableArray* keys = [NSMutableArray array]; + NSMutableArray *keys = [NSMutableArray array]; BOOL removeFromHiddenKeys = TRUE; - if([@"enable_video_preference" compare: notif.object] == NSOrderedSame) { - removeFromHiddenKeys = [[notif.userInfo objectForKey:@"enable_video_preference"] boolValue]; + if ([@"enable_video_preference" compare:notif.object] == NSOrderedSame) { + removeFromHiddenKeys = [[notif.userInfo objectForKey:@"enable_video_preference"] boolValue]; [keys addObject:@"video_menu"]; - } else if ([@"random_port_preference" compare: notif.object] == NSOrderedSame) { - removeFromHiddenKeys = ! [[notif.userInfo objectForKey:@"random_port_preference"] boolValue]; + } else if ([@"random_port_preference" compare:notif.object] == NSOrderedSame) { + removeFromHiddenKeys = ![[notif.userInfo objectForKey:@"random_port_preference"] boolValue]; [keys addObject:@"port_preference"]; - } else if ([@"backgroundmode_preference" compare: notif.object] == NSOrderedSame) { + } else if ([@"backgroundmode_preference" compare:notif.object] == NSOrderedSame) { removeFromHiddenKeys = [[notif.userInfo objectForKey:@"backgroundmode_preference"] boolValue]; [keys addObject:@"start_at_boot_preference"]; - } else if ([@"stun_preference" compare: notif.object] == NSOrderedSame) { + } else if ([@"stun_preference" compare:notif.object] == NSOrderedSame) { NSString *stun_server = [notif.userInfo objectForKey:@"stun_preference"]; removeFromHiddenKeys = (stun_server && ([stun_server length] > 0)); [keys addObject:@"ice_preference"]; - } else if ([@"debugenable_preference" compare: notif.object] == NSOrderedSame) { + } else if ([@"debugenable_preference" compare:notif.object] == NSOrderedSame) { BOOL debugEnabled = [[notif.userInfo objectForKey:@"debugenable_preference"] boolValue]; removeFromHiddenKeys = debugEnabled; - [keys addObject:@"send_logs_button"]; + [keys addObject:@"send_logs_button"]; [keys addObject:@"reset_logs_button"]; [[LinphoneManager instance] setLogsEnabled:debugEnabled]; - } else if( [@"advanced_account_preference" compare:notif.object] == NSOrderedSame) { + } else if ([@"advanced_account_preference" compare:notif.object] == NSOrderedSame) { removeFromHiddenKeys = [[notif.userInfo objectForKey:@"advanced_account_preference"] boolValue]; - [keys addObject:@"userid_preference"]; [keys addObject:@"proxy_preference"]; [keys addObject:@"outbound_proxy_preference"]; [keys addObject:@"avpf_preference"]; + } else if ([@"video_preset_preference" compare:notif.object] == NSOrderedSame) { + NSString *video_preset = [notif.userInfo objectForKey:@"video_preset_preference"]; + removeFromHiddenKeys = [video_preset isEqualToString:@"custom"]; + [keys addObject:@"video_preferred_fps_preference"]; + [keys addObject:@"download_bandwidth_preference"]; } - for(NSString* key in keys){ - if( removeFromHiddenKeys ) [hiddenKeys removeObject:key]; - else [hiddenKeys addObject:key]; + for (NSString *key in keys) { + if (removeFromHiddenKeys) + [hiddenKeys removeObject:key]; + else + [hiddenKeys addObject:key]; } [settingsController setHiddenKeys:hiddenKeys animated:TRUE]; - } - #pragma mark - -+ (IASKSpecifier*)disableCodecSpecifier:(IASKSpecifier *)specifier { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; ++ (IASKSpecifier *)disableCodecSpecifier:(IASKSpecifier *)specifier { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - NSMutableString *type = [NSMutableString stringWithString:[dict objectForKey:kIASKType]]; - [type setString:kIASKPSTitleValueSpecifier]; - [dict setObject:type forKey:kIASKType]; + NSMutableString *type = [NSMutableString stringWithString:[dict objectForKey:kIASKType]]; + [type setString:kIASKPSTitleValueSpecifier]; + [dict setObject:type forKey:kIASKType]; - NSMutableArray *values = [NSMutableArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:1], nil ]; - [dict setObject:values forKey:kIASKValues]; + NSMutableArray *values = + [NSMutableArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:1], nil]; + [dict setObject:values forKey:kIASKValues]; - NSString* title = NSLocalizedString(@"Disabled, build from sources to enable", nil); - NSMutableArray *titles = [NSMutableArray arrayWithObjects:title, title, nil]; - [dict setObject:titles forKey:kIASKTitles]; + NSString *title = NSLocalizedString(@"Disabled, build from sources to enable", nil); + NSMutableArray *titles = [NSMutableArray arrayWithObjects:title, title, nil]; + [dict setObject:titles forKey:kIASKTitles]; - return [[IASKSpecifier alloc] initWithSpecifier:dict]; + return [[IASKSpecifier alloc] initWithSpecifier:dict]; } -+ (IASKSpecifier*)filterSpecifier:(IASKSpecifier *)specifier { ++ (IASKSpecifier *)filterSpecifier:(IASKSpecifier *)specifier { #ifndef HAVE_SSL - if ([[specifier key] isEqualToString:@"transport_preference"]) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"TLS"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"tls"]; - [dict setObject:values forKey:@"Values"]; - return [[IASKSpecifier alloc] initWithSpecifier:dict]; - } + if ([[specifier key] isEqualToString:@"transport_preference"]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"TLS"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"tls"]; + [dict setObject:values forKey:@"Values"]; + return [[IASKSpecifier alloc] initWithSpecifier:dict]; + } #else - if ([[specifier key] isEqualToString:@"media_encryption_preference"]) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; - if(!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionZRTP)) { - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"ZRTP"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"ZRTP"]; - [dict setObject:values forKey:@"Values"]; - } - if(!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionSRTP)) { - NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; - [titles removeObject:@"SRTP"]; - [dict setObject:titles forKey:@"Titles"]; - NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; - [values removeObject:@"SRTP"]; - [dict setObject:values forKey:@"Values"]; - } - if(!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionDTLS)) { + if ([[specifier key] isEqualToString:@"media_encryption_preference"]) { + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[specifier specifierDict]]; + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionZRTP)) { + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"ZRTP"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"ZRTP"]; + [dict setObject:values forKey:@"Values"]; + } + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionSRTP)) { + NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; + [titles removeObject:@"SRTP"]; + [dict setObject:titles forKey:@"Titles"]; + NSMutableArray *values = [NSMutableArray arrayWithArray:[dict objectForKey:@"Values"]]; + [values removeObject:@"SRTP"]; + [dict setObject:values forKey:@"Values"]; + } + if (!linphone_core_media_encryption_supported([LinphoneManager getLc], LinphoneMediaEncryptionDTLS)) { NSMutableArray *titles = [NSMutableArray arrayWithArray:[dict objectForKey:@"Titles"]]; [titles removeObject:@"DTLS"]; [dict setObject:titles forKey:@"Titles"]; @@ -566,127 +563,135 @@ static UICompositeViewDescription *compositeDescription = nil; [values removeObject:@"DTLS"]; [dict setObject:values forKey:@"Values"]; } - return [[IASKSpecifier alloc] initWithSpecifier:dict]; - } + return [[IASKSpecifier alloc] initWithSpecifier:dict]; + } -#endif //HAVE_SSL +#endif // HAVE_SSL + // Add "build from source" if MPEG4 or H264 disabled + if ([[specifier key] isEqualToString:@"h264_preference"] && ![LinphoneManager isCodecSupported:"h264"]) { + return [SettingsViewController disableCodecSpecifier:specifier]; + } + if ([[specifier key] isEqualToString:@"mp4v-es_preference"] && ![LinphoneManager isCodecSupported:"mp4v-es"]) { + return [SettingsViewController disableCodecSpecifier:specifier]; + } - // Add "build from source" if MPEG4 or H264 disabled - if ([[specifier key] isEqualToString:@"h264_preference"] && ![LinphoneManager isCodecSupported:"h264"]) { - return [SettingsViewController disableCodecSpecifier:specifier]; - } - if ([[specifier key] isEqualToString:@"mp4v-es_preference"] && ![LinphoneManager isCodecSupported:"mp4v-es"]) { - return [SettingsViewController disableCodecSpecifier:specifier]; - } - - return specifier; + return specifier; } -- (NSSet*)findHiddenKeys { - LinphoneManager* lm = [LinphoneManager instance]; - NSMutableSet *hiddenKeys = [NSMutableSet set]; +- (NSSet *)findHiddenKeys { + LinphoneManager *lm = [LinphoneManager instance]; + NSMutableSet *hiddenKeys = [NSMutableSet set]; #ifndef HAVE_SSL [hiddenKeys addObject:@"media_encryption_preference"]; #endif #ifndef DEBUG - [hiddenKeys addObject:@"release_button"]; - [hiddenKeys addObject:@"clear_cache_button"]; - [hiddenKeys addObject:@"battery_alert_button"]; + [hiddenKeys addObject:@"release_button"]; + [hiddenKeys addObject:@"clear_cache_button"]; + [hiddenKeys addObject:@"battery_alert_button"]; #endif - if (! [[LinphoneManager instance] lpConfigBoolForKey:@"debugenable_preference"]) { + if (![[LinphoneManager instance] lpConfigBoolForKey:@"debugenable_preference"]) { [hiddenKeys addObject:@"send_logs_button"]; [hiddenKeys addObject:@"reset_logs_button"]; } - [hiddenKeys addObject:@"playback_gain_preference"]; - [hiddenKeys addObject:@"microphone_gain_preference"]; + [hiddenKeys addObject:@"playback_gain_preference"]; + [hiddenKeys addObject:@"microphone_gain_preference"]; - [hiddenKeys addObject:@"network_limit_group"]; - [hiddenKeys addObject:@"upload_bandwidth_preference"]; - [hiddenKeys addObject:@"download_bandwidth_preference"]; + [hiddenKeys addObject:@"network_limit_group"]; - [hiddenKeys addObject:@"incoming_call_timeout_preference"]; - [hiddenKeys addObject:@"in_call_timeout_preference"]; + [hiddenKeys addObject:@"incoming_call_timeout_preference"]; + [hiddenKeys addObject:@"in_call_timeout_preference"]; - [hiddenKeys addObject:@"wifi_only_preference"]; + [hiddenKeys addObject:@"wifi_only_preference"]; - [hiddenKeys addObject:@"quit_button"]; // Hide for the moment - [hiddenKeys addObject:@"about_button"]; // Hide for the moment + [hiddenKeys addObject:@"quit_button"]; // Hide for the moment + [hiddenKeys addObject:@"about_button"]; // Hide for the moment - if (!linphone_core_video_supported([LinphoneManager getLc])) - [hiddenKeys addObject:@"video_menu"]; + if (!linphone_core_video_supported([LinphoneManager getLc])) + [hiddenKeys addObject:@"video_menu"]; - if (![LinphoneManager isNotIphone3G]) - [hiddenKeys addObject:@"silk_24k_preference"]; + if (![LinphoneManager isNotIphone3G]) + [hiddenKeys addObject:@"silk_24k_preference"]; - UIDevice* device = [UIDevice currentDevice]; - if (![device respondsToSelector:@selector(isMultitaskingSupported)] || ![device isMultitaskingSupported]) { - [hiddenKeys addObject:@"backgroundmode_preference"]; - [hiddenKeys addObject:@"start_at_boot_preference"]; - } else { - if(![lm lpConfigBoolForKey:@"backgroundmode_preference"]) { - [hiddenKeys addObject:@"start_at_boot_preference"]; - } - } + UIDevice *device = [UIDevice currentDevice]; + if (![device respondsToSelector:@selector(isMultitaskingSupported)] || ![device isMultitaskingSupported]) { + [hiddenKeys addObject:@"backgroundmode_preference"]; + [hiddenKeys addObject:@"start_at_boot_preference"]; + } else { + if (![lm lpConfigBoolForKey:@"backgroundmode_preference"]) { + [hiddenKeys addObject:@"start_at_boot_preference"]; + } + } - [hiddenKeys addObject:@"enable_first_login_view_preference"]; + [hiddenKeys addObject:@"enable_first_login_view_preference"]; #ifndef VIDEO_ENABLED - [hiddenKeys addObject:@"enable_video_preference"]; -#endif //VIDEO_ENABLED + [hiddenKeys addObject:@"enable_video_preference"]; +#endif // VIDEO_ENABLED - if (!linphone_core_video_enabled([LinphoneManager getLc])) { - [hiddenKeys addObject:@"video_menu"]; - } + if (!linphone_core_video_enabled([LinphoneManager getLc])) { + [hiddenKeys addObject:@"video_menu"]; + } + if (!linphone_core_get_video_preset([LinphoneManager getLc]) || + strcmp(linphone_core_get_video_preset([LinphoneManager getLc]), "custom") != 0) { + [hiddenKeys addObject:@"video_preferred_fps_preference"]; + [hiddenKeys addObject:@"download_bandwidth_preference"]; + } - [hiddenKeys addObjectsFromArray:[[LinphoneManager unsupportedCodecs] allObjects]]; + [hiddenKeys addObjectsFromArray:[[LinphoneManager unsupportedCodecs] allObjects]]; - BOOL random_port = [lm lpConfigBoolForKey:@"random_port_preference"]; - if(random_port) { - [hiddenKeys addObject:@"port_preference"]; - } + BOOL random_port = [lm lpConfigBoolForKey:@"random_port_preference"]; + if (random_port) { + [hiddenKeys addObject:@"port_preference"]; + } - if(linphone_core_get_stun_server([LinphoneManager getLc]) == NULL) { - [hiddenKeys addObject:@"ice_preference"]; - } + if (linphone_core_get_stun_server([LinphoneManager getLc]) == NULL) { + [hiddenKeys addObject:@"ice_preference"]; + } - if(![lm lpConfigBoolForKey:@"debugenable_preference"]) { - [hiddenKeys addObject:@"console_button"]; - } + if (![lm lpConfigBoolForKey:@"debugenable_preference"]) { + [hiddenKeys addObject:@"console_button"]; + } - if(![LinphoneManager runningOnIpad]) { - [hiddenKeys addObject:@"preview_preference"]; - } - if([lm lpConfigBoolForKey:@"hide_run_assistant_preference"]) { + if (![LinphoneManager runningOnIpad]) { + [hiddenKeys addObject:@"preview_preference"]; + } + if ([lm lpConfigBoolForKey:@"hide_run_assistant_preference"]) { [hiddenKeys addObject:@"wizard_button"]; } - if (!linphone_core_tunnel_available()){ + if (!linphone_core_tunnel_available()) { [hiddenKeys addObject:@"tunnel_menu"]; } - if( ![lm lpConfigBoolForKey:@"advanced_account_preference"] ){ - [hiddenKeys addObject:@"userid_preference"]; - [hiddenKeys addObject:@"proxy_preference"]; - [hiddenKeys addObject:@"outbound_proxy_preference"]; - [hiddenKeys addObject:@"avpf_preference"]; - } + if (![lm lpConfigBoolForKey:@"advanced_account_preference"]) { + [hiddenKeys addObject:@"userid_preference"]; + [hiddenKeys addObject:@"proxy_preference"]; + [hiddenKeys addObject:@"outbound_proxy_preference"]; + [hiddenKeys addObject:@"avpf_preference"]; + } if (![[[LinphoneManager instance] iapManager] enabled]) { [hiddenKeys addObject:@"in_app_products_button"]; } - return hiddenKeys; + if ([[UIDevice currentDevice].systemVersion floatValue] < 8) { + [hiddenKeys addObject:@"repeat_call_notification_preference"]; + } + + return hiddenKeys; } - (void)goToWizard { - WizardViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[WizardViewController compositeViewDescription]], WizardViewController); - if(controller != nil) { + WizardViewController *controller = + DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[WizardViewController compositeViewDescription]], + WizardViewController); + if (controller != nil) { [controller reset]; } } @@ -696,57 +701,66 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)settingsViewControllerDidEnd:(IASKAppSettingsViewController *)sender { } -- (void)settingsViewController:(IASKAppSettingsViewController*)sender buttonTappedForSpecifier:(IASKSpecifier*)specifier { - NSString *key = [specifier.specifierDict objectForKey:kIASKKey]; - LinphoneCore* lc = [LinphoneManager getLc]; +- (void)settingsViewController:(IASKAppSettingsViewController *)sender + buttonTappedForSpecifier:(IASKSpecifier *)specifier { + NSString *key = [specifier.specifierDict objectForKey:kIASKKey]; + LinphoneCore *lc = [LinphoneManager getLc]; #ifdef DEBUG - if([key isEqual:@"release_button"]) { - [UIApplication sharedApplication].keyWindow.rootViewController = nil; - [[UIApplication sharedApplication].keyWindow setRootViewController:nil]; - [[LinphoneManager instance] destroyLinphoneCore]; - [LinphoneManager instanceRelease]; - } else if([key isEqual:@"clear_cache_button"]) { - [[PhoneMainView instance].mainViewController clearCache:[NSArray arrayWithObject:[[PhoneMainView instance] currentView]]]; - } else if([key isEqual:@"battery_alert_button"]) { - [[UIDevice currentDevice] _setBatteryState:UIDeviceBatteryStateUnplugged]; - [[UIDevice currentDevice] _setBatteryLevel:0.01f]; - [[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceBatteryLevelDidChangeNotification object:self]; - } + if ([key isEqual:@"release_button"]) { + [UIApplication sharedApplication].keyWindow.rootViewController = nil; + [[UIApplication sharedApplication].keyWindow setRootViewController:nil]; + [[LinphoneManager instance] destroyLinphoneCore]; + [LinphoneManager instanceRelease]; + } else if ([key isEqual:@"clear_cache_button"]) { + [[PhoneMainView instance] + .mainViewController clearCache:[NSArray arrayWithObject:[[PhoneMainView instance] currentView]]]; + } else if ([key isEqual:@"battery_alert_button"]) { + [[UIDevice currentDevice] _setBatteryState:UIDeviceBatteryStateUnplugged]; + [[UIDevice currentDevice] _setBatteryLevel:0.01f]; + [[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceBatteryLevelDidChangeNotification + object:self]; + } #endif - if([key isEqual:@"wizard_button"]) { - if (linphone_core_get_default_proxy_config(lc) == NULL ) { + if ([key isEqual:@"wizard_button"]) { + if (linphone_core_get_default_proxy_config(lc) == NULL) { [self goToWizard]; return; } - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Warning",nil) - message:NSLocalizedString(@"Launching the Wizard will delete any existing proxy config.\nAre you sure to want it?",nil) - delegate:self - cancelButtonTitle:NSLocalizedString(@"Cancel",nil) - otherButtonTitles:NSLocalizedString(@"Launch Wizard",nil), nil]; - [alert show]; - } else if ( [key isEqual:@"clear_proxy_button"] ) { - if ( linphone_core_get_default_proxy_config(lc) == NULL ) { + UIAlertView *alert = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Warning", nil) + message: + NSLocalizedString( + @"Launching the Wizard will delete any existing proxy config.\nAre you sure to want it?", + nil) + delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) + otherButtonTitles:NSLocalizedString(@"Launch Wizard", nil), nil]; + [alert show]; + } else if ([key isEqual:@"clear_proxy_button"]) { + if (linphone_core_get_default_proxy_config(lc) == NULL) { return; } - DTAlertView* alert = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Warning", nil) message:NSLocalizedString(@"Are you sure to want to clear your proxy setup?",nil)]; + DTAlertView *alert = [[DTAlertView alloc] + initWithTitle:NSLocalizedString(@"Warning", nil) + message:NSLocalizedString(@"Are you sure to want to clear your proxy setup?", nil)]; [alert addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; [alert addButtonWithTitle:NSLocalizedString(@"Yes", nil) block:^{ - linphone_core_clear_proxy_config(lc); - linphone_core_clear_all_auth_info(lc); - [settingsStore transformLinphoneCoreToKeys]; - [settingsController.tableView reloadData]; + linphone_core_clear_proxy_config(lc); + linphone_core_clear_all_auth_info(lc); + [settingsStore transformLinphoneCoreToKeys]; + [settingsController.tableView reloadData]; }]; [alert show]; - } else if([key isEqual:@"about_button"]) { - [[PhoneMainView instance] changeCurrentView:[AboutViewController compositeViewDescription] push:TRUE]; + } else if ([key isEqual:@"about_button"]) { + [[PhoneMainView instance] changeCurrentView:[AboutViewController compositeViewDescription] push:TRUE]; } else if ([key isEqualToString:@"reset_logs_button"]) { linphone_core_reset_log_collection(); } else if ([key isEqual:@"send_logs_button"]) { - char * filepath = linphone_core_compress_log_collection(lc); + char *filepath = linphone_core_compress_log_collection(lc); if (filepath == NULL) { LOGE(@"Cannot sent logs: file is NULL"); return; @@ -768,59 +782,66 @@ static UICompositeViewDescription *compositeDescription = nil; LOGE(@"Unknown extension type: %@, cancelling email", filename); return; } - [self emailAttachment:[NSData dataWithContentsOfFile:[NSString stringWithUTF8String:filepath]] mimeType:mimeType name:filename]; + [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]; } } #pragma mark - UIAlertView delegate - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { - if( buttonIndex != 1 ) return; /* cancel */ - else [self goToWizard]; + if (buttonIndex != 1) + return; /* cancel */ + else + [self goToWizard]; } #pragma mark - Mail composer for send log -- (void)emailAttachment: (NSData*)attachment mimeType:(NSString*)type name:(NSString*)attachmentName -{ +- (void)emailAttachment:(NSData *)attachment mimeType:(NSString *)type name:(NSString *)attachmentName { if (attachmentName == nil || type == nil || attachmentName == nil) { LOGE(@"Trying to email attachment but mandatory field is missing"); return; } #if TARGET_IPHONE_SIMULATOR - UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cannot send email",nil) - message:NSLocalizedString(@"Simulator cannot send emails. To test this feature, please use a real device.",nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue",nil) - otherButtonTitles:nil]; + UIAlertView *error = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Cannot send email", nil) + message:NSLocalizedString( + @"Simulator cannot send emails. To test this feature, please use a real device.", nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Continue", nil) + otherButtonTitles:nil]; [error show]; #else if ([MFMailComposeViewController canSendMail] == YES) { MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init]; picker.mailComposeDelegate = self; - [picker setSubject:NSLocalizedString(@"Linphone Logs",nil)]; + [picker setSubject:NSLocalizedString(@"Linphone Logs", nil)]; [picker setToRecipients:[NSArray arrayWithObjects:@"linphone-iphone@belledonne-communications.com", nil]]; [picker setMessageBody:NSLocalizedString(@"Linphone logs", nil) isHTML:NO]; [picker addAttachmentData:attachment mimeType:type fileName:attachmentName]; [self presentViewController:picker animated:true completion:nil]; } else { - UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cannot send email",nil) - message:NSLocalizedString(@"Your device is not configured to send emails. Please configure mail application prior to send logs.",nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"Continue",nil) - otherButtonTitles:nil]; + UIAlertView *error = [[UIAlertView alloc] + initWithTitle:NSLocalizedString(@"Cannot send email", nil) + message:NSLocalizedString(@"Your device is not configured to send emails. Please configure mail " + @"application prior to send logs.", + nil) + delegate:nil + cancelButtonTitle:NSLocalizedString(@"Continue", nil) + otherButtonTitles:nil]; [error show]; } #endif } -- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error -{ +- (void)mailComposeController:(MFMailComposeViewController *)controller + didFinishWithResult:(MFMailComposeResult)result + error:(NSError *)error { if (error != nil) { LOGW(@"Error while sending mail: %@", error); } else { 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..36419cbf4 --- /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 { + 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] + 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), + }]; + 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 + 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/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m b/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m index 6e1791aec..533eb508b 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; 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/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..76cd623c5 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,100 @@ 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) { +#if TARGET_IPHONE_SIMULATOR + [tester acknowledgeSystemAlert]; +#endif + } + + [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]; + // 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); +} + +- (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/licenses.html b/Resources/licenses.html index 31b1bdba7..183077683 100644 --- a/Resources/licenses.html +++ b/Resources/licenses.html @@ -37,6 +37,11 @@ http://www.tortuga22.com
Apache license

+

Ryan Maxwell

+

UIAlertview+Blocks

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

OrderedDictionary

Matt Gallagher
http://cocoawithlove.com

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/Resources/wizard_linphone_create.rc b/Resources/wizard_linphone_create.rc index 292d662d4..e023f4454 100644 --- a/Resources/wizard_linphone_create.rc +++ b/Resources/wizard_linphone_create.rc @@ -22,7 +22,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 2244776e8..1e71c41d3 100644 --- a/Resources/wizard_linphone_existing.rc +++ b/Resources/wizard_linphone_existing.rc @@ -22,7 +22,7 @@
1 - https://www.linphone.org:444/upload.php + https://www.linphone.org:444/lft.php 1 stun.linphone.org 1 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/Call.plist b/Settings/InAppSettings.bundle/Call.plist index ae0855c79..61ec80f69 100644 --- a/Settings/InAppSettings.bundle/Call.plist +++ b/Settings/InAppSettings.bundle/Call.plist @@ -106,6 +106,16 @@ IASKTextAlignment IASKUITextAlignmentRight + + DefaultValue + + Key + repeat_call_notification_preference + Title + Repeat call notification + Type + PSToggleSwitchSpecifier + 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 a3ad75a6c..dedc25c2d 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 @@ -276,7 +268,7 @@ Key release_button Title - Exit + Release core Type IASKButtonSpecifier diff --git a/Settings/InAppSettings.bundle/Video.plist b/Settings/InAppSettings.bundle/Video.plist index 71e8964ff..4d72625e6 100644 --- a/Settings/InAppSettings.bundle/Video.plist +++ b/Settings/InAppSettings.bundle/Video.plist @@ -41,8 +41,28 @@ preview_preference + Key + video_preset_preference + Title + Video preset + Titles + + Default + High FPS + Custom + + Type + PSMultiValueSpecifier + Values + + default + high-fps + custom + DefaultValue - 1 + default + + Key video_preferred_size_preference Title @@ -61,6 +81,56 @@ 1 2 + DefaultValue + 1 + + + Key + video_preferred_fps_preference + Title + Preferred FPS + Type + PSMultiValueSpecifier + Titles + + No preference + 5 + 10 + 15 + 20 + 25 + 30 + + Values + + 0 + 5 + 10 + 15 + 20 + 25 + 30 + + DefaultValue + 0 + + + Key + download_bandwidth_preference + Title + Bandwidth limit in kbits/s + Type + PSTextFieldSpecifier + AutocapitalizationType + None + AutocorrectionType + No + KeyboardType + NumberPad + DefaultValue + 380 + IASKTextAlignment + IASKUITextAlignmentRight Title diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index cc23c79d1..b96c6ad3b 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -111,20 +111,17 @@ 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 */; }; 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 */; }; 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 */; }; @@ -305,7 +302,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 */; }; @@ -891,7 +887,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 = ""; }; @@ -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 = ""; }; @@ -1038,6 +1025,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 = ""; }; @@ -1257,8 +1246,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 = ""; }; @@ -1865,6 +1852,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 */, @@ -2039,21 +2027,11 @@ D38187D415FE346B00C3EDCA /* HistoryViewController.xib */, D378AB2815DCDB480098505D /* ImagePickerViewController.h */, D378AB2915DCDB490098505D /* ImagePickerViewController.m */, - D374D3FB16071762003D25FF /* ImageSharing.h */, - D374D3FC16071762003D25FF /* ImageSharing.m */, 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 */, @@ -2317,7 +2295,6 @@ D30BF33216A427BC00AF0026 /* libtunnel.a */, 7066FC0B13E830E400EFC6DC /* libvpx.a */, 22AA8AFB13D7125500B30535 /* libx264.a */, - 15017E6F1773578400784ACB /* libxml2.a */, F0B89C2118DC89E30050B60E /* MediaPlayer.framework */, D37DC7171594AF3400B2A5EB /* MessageUI.framework */, 226EF06B15FA256B005865C7 /* MobileCoreServices.framework */, @@ -2343,6 +2320,8 @@ D37EE15F160377D7003608A6 /* DTFoundation */, D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */, D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */, + 6371579F1B283FE200C91677 /* FileTransferDelegate.h */, + 637157A01B283FE200C91677 /* FileTransferDelegate.m */, D3ED40141602172200BF332B /* GrowingTextView */, D3807FC715C2894A005BE9BC /* InAppSettingsKit */, D3B90E1115C2CB5700F64F8C /* NinePatch.xcodeproj */, @@ -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,18 +4029,15 @@ 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 */, 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/prepare.py b/prepare.py index 50dd95b81..ac9fdfc30 100755 --- a/prepare.py +++ b/prepare.py @@ -27,12 +27,14 @@ 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 class IOSTarget(prepare.Target): + def __init__(self, arch): prepare.Target.__init__(self, 'ios-' + arch) current_path = os.path.dirname(os.path.realpath(__file__)) @@ -40,62 +42,77 @@ class IOSTarget(prepare.Target): 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' + '-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) + 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) + shutil.rmtree( + 'liblinphone-sdk', ignore_errors=False, onerror=self.handle_remove_read_only) class IOSi386Target(IOSTarget): + def __init__(self): IOSTarget.__init__(self, 'i386') + class IOSx8664Target(IOSTarget): + def __init__(self): IOSTarget.__init__(self, 'x86_64') + class IOSarmv7Target(IOSTarget): + def __init__(self): IOSTarget.__init__(self, 'armv7') + class IOSarm64Target(IOSTarget): + 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]))) + 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') + 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(""" *************************************************************************** @@ -121,17 +138,52 @@ def warning(platforms): """) -def main(argv = None): +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)) + + +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 - 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]))) + 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() + selected_platforms = [] for platform in args.platform: if platform == 'all': @@ -152,14 +204,18 @@ 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) + 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 = "" @@ -167,6 +223,12 @@ def main(argv = None): 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; \\ @@ -182,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_$*/*; \\ @@ -226,7 +288,7 @@ def main(argv = None): multiarch = "" for arch in makefile_platforms[1:]: multiarch += \ -""" if test -f "$${arch}_path"; then \\ + """ if test -f "$${arch}_path"; then \\ all_paths=`echo $$all_paths $${arch}_path`; \\ all_archs="$$all_archs,{arch}" ; \\ else \\ @@ -236,6 +298,7 @@ def main(argv = None): makefile = """ archs={archs} packages={packages} +libs_list={libs_list} LINPHONE_IPHONE_VERSION=$(shell git describe --always) .PHONY: all @@ -249,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-$*; \\ @@ -292,9 +355,17 @@ 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_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 ipa: build xcodebuild -configuration Release \\ @@ -318,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}" @@ -339,7 +415,9 @@ 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], 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() diff --git a/submodules/belle-sip b/submodules/belle-sip index 611762072..7780031ed 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 611762072933bf7bcbac9848bfead5a367a22ded +Subproject commit 7780031ed6742e6653c3718ed506c851d129f86f 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 a4910d080..7f9f9467f 100644 Binary files a/submodules/binaries/libdummy.a and b/submodules/binaries/libdummy.a differ 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 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 diff --git a/submodules/linphone b/submodules/linphone index ad1d7c12c..b843685bd 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit ad1d7c12c9b459660b34d63408b144bf5890f3b6 +Subproject commit b843685bd8e03b047bc85239397bd1961ff9a9a0 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 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