From 4a136403b4911eefd961b3bd3b382296cfe7e213 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 19 May 2014 16:57:52 +0200 Subject: [PATCH] First version of internal storage use for iOS --- Classes/ChatRoomTableViewController.h | 13 +- Classes/ChatRoomTableViewController.m | 127 ++++--- Classes/ChatRoomViewController.h | 4 +- Classes/ChatRoomViewController.m | 121 ++----- Classes/ChatTableViewController.h | 4 +- Classes/ChatTableViewController.m | 28 +- Classes/ChatViewController.m | 4 +- Classes/ContactDetailsTableViewController.m | 3 +- Classes/HistoryDetailsViewController.m | 3 +- Classes/LinphoneAppDelegate.m | 21 +- Classes/LinphoneManager.h | 1 + Classes/LinphoneManager.m | 188 ++++++---- Classes/LinphoneUI/UIChatCell.h | 5 +- Classes/LinphoneUI/UIChatCell.m | 72 ++-- Classes/LinphoneUI/UIChatRoomCell.h | 8 +- Classes/LinphoneUI/UIChatRoomCell.m | 83 +++-- Classes/LinphoneUI/UIMainBar.m | 8 +- Classes/Model/ChatModel.h | 59 --- Classes/Model/ChatModel.m | 379 -------------------- Classes/PhoneMainView.m | 10 +- 20 files changed, 376 insertions(+), 765 deletions(-) delete mode 100644 Classes/Model/ChatModel.h delete mode 100644 Classes/Model/ChatModel.m diff --git a/Classes/ChatRoomTableViewController.h b/Classes/ChatRoomTableViewController.h index 09de79e8c..38fc39114 100644 --- a/Classes/ChatRoomTableViewController.h +++ b/Classes/ChatRoomTableViewController.h @@ -19,27 +19,28 @@ #import -#import "ChatModel.h" +#include "linphone/linphonecore.h" @protocol ChatRoomDelegate - (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo; - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url; -- (void)resendChat:(NSString*)message; +- (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url; @end @interface ChatRoomTableViewController : UITableViewController { @private - NSMutableArray *data; + LinphoneChatRoom* chatRoom; + MSList *messageList; } -@property (nonatomic, copy) NSString *remoteAddress; @property (nonatomic, retain) id chatRoomDelegate; -- (void)addChatEntry:(ChatModel*)chat; +- (void)addChatEntry:(LinphoneChatMessage*)chat; - (void)scrollToBottom:(BOOL)animated; - (void)scrollToLastUnread:(BOOL)animated; -- (void)updateChatEntry:(ChatModel*)chat; +- (void)updateChatEntry:(LinphoneChatMessage*)chat; +- (void)setChatRoom:(LinphoneChatRoom*)room; @end diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 2476edc2a..3969d097f 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -27,14 +27,13 @@ @implementation ChatRoomTableViewController -@synthesize remoteAddress; @synthesize chatRoomDelegate; #pragma mark - Lifecycle Functions - (void)dealloc { - [remoteAddress release]; [chatRoomDelegate release]; + [self clearMessageList]; [super dealloc]; } @@ -44,82 +43,98 @@ - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [TUNinePatchCache flushCache]; // Clear cache - if(data != nil) { - [data removeAllObjects]; - [data release]; - data = nil; - } + [self clearMessageList]; + chatRoom = NULL; } - (void)viewWillAppear:(BOOL)animated { - [self loadData]; + [self reloadData]; } #pragma mark - -- (void)loadData { - if(data != nil) { - [data removeAllObjects]; - [data release]; +- (void)clearMessageList { + if (messageList){ + ms_list_free_with_data(messageList, (void(*)(void*))linphone_chat_message_unref); + messageList = nil; } - data = [[ChatModel listMessages:remoteAddress] retain]; - [[self tableView] reloadData]; +} + +- (void)updateData { + if( !chatRoom ) return; + [self clearMessageList]; + self->messageList = linphone_chat_room_get_history(chatRoom, 0); +} + +- (void)reloadData { + [self updateData]; + [self.tableView reloadData]; [self scrollToLastUnread:false]; } -- (void)addChatEntry:(ChatModel*)chat { - if(data == nil) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot add entry: null data"]; - return; - } +- (void)addChatEntry:(LinphoneChatMessage*)chat { + + messageList = ms_list_append(messageList, chat); + int pos = ms_list_size(messageList) - 1; + [self.tableView beginUpdates]; - int pos = [data count]; - [data insertObject:chat atIndex:pos]; - [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:pos inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; + [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:pos inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView endUpdates]; } -- (void)updateChatEntry:(ChatModel*)chat { - if(data == nil) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update entry: null data"]; - return; - } - NSInteger index = [data indexOfObject:chat]; +- (void)updateChatEntry:(LinphoneChatMessage*)chat { + NSInteger index = ms_list_index(self->messageList, chat); if (index<0) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"chat entries diesn not exixt"]; + [LinphoneLogger logc:LinphoneLoggerWarning format:"chat entry doesn't exist"]; return; } - [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:FALSE];; //just reload + [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:FALSE]; //just reload return; } - (void)scrollToBottom:(BOOL)animated { [self.tableView reloadData]; - if( [data count] ){ - [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([data count] - 1) inSection:0] + int count = ms_list_size(messageList); + if( count ){ + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; } } +- (void)debugMessages { + if( !messageList ){ + NSLog(@"No data to debug"); + return; + } + MSList*item = self->messageList; + int count = 0; + while (item) { + LinphoneChatMessage* msg = (LinphoneChatMessage*)item->data; + NSLog(@"Message %d: %s", count++, linphone_chat_message_get_text(msg)); + item = item->next; + } +} + - (void)scrollToLastUnread:(BOOL)animated { - if(data == nil) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot add entry: null data"]; + if(messageList == nil || chatRoom == nil) { return; } int index = -1; + int count = ms_list_size(messageList); // Find first unread & set all entry read - for(int i = 0; i <[data count]; ++i) { - ChatModel *chat = [data objectAtIndex:i]; - if([[chat read] intValue] == 0) { - [chat setRead:[NSNumber numberWithInt:1]]; + for(int i = 0; i = 0) { @@ -132,15 +147,11 @@ #pragma mark - Property Functions -- (void)setRemoteAddress:(NSString *)aremoteAddress { - if(remoteAddress != nil) { - [remoteAddress release]; - } - self->remoteAddress = [aremoteAddress copy]; - [self loadData]; +- (void)setChatRoom:(LinphoneChatRoom*)room { + chatRoom = room; + [self reloadData]; } - #pragma mark - UITableViewDataSource Functions - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -148,7 +159,7 @@ } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return [data count]; + return ms_list_size(self->messageList); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -157,8 +168,9 @@ if (cell == nil) { cell = [[[UIChatRoomCell alloc] initWithIdentifier:kCellId] autorelease]; } - - [cell setChat:[data objectAtIndex:[indexPath row]]]; + + LinphoneChatMessage* chat = ms_list_nth_data(self->messageList, [indexPath row]); + [cell setChatMessage:chat]; [cell setChatRoomDelegate:chatRoomDelegate]; return cell; } @@ -169,11 +181,16 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if(editingStyle == UITableViewCellEditingStyleDelete) { [tableView beginUpdates]; - ChatModel *chat = [data objectAtIndex:[indexPath row]]; - [data removeObjectAtIndex:[indexPath row]]; - [chat delete]; - [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom]; + LinphoneChatMessage *chat = ms_list_nth_data(self->messageList, [indexPath row]); + if( chat ){ + + linphone_chat_room_delete_message(chatRoom, chat); + messageList = ms_list_remove(messageList, chat); + + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom]; + } [tableView endUpdates]; + } } @@ -186,8 +203,8 @@ } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - ChatModel *chat = [data objectAtIndex:[indexPath row]]; - return [UIChatRoomCell height:chat width:[self.view frame].size.width]; + LinphoneChatMessage* message = ms_list_nth_data(self->messageList, [indexPath row]); + return [UIChatRoomCell height:message width:[self.view frame].size.width]; } @end diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index 0150980f9..491accaf4 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -23,7 +23,6 @@ #import "UICompositeViewController.h" #import "ChatRoomTableViewController.h" #import "HPGrowingTextView.h" -#import "ChatModel.h" #import "ImagePickerViewController.h" #import "ImageSharing.h" #import "OrderedDictionary.h" @@ -53,7 +52,6 @@ @property (retain, nonatomic) IBOutlet UILabel *composeLabel; @property (retain, nonatomic) IBOutlet UIView *composeIndicatorView; -@property (nonatomic, copy) NSString *remoteAddress; @property (nonatomic, retain) IBOutlet UIButton* pictureButton; @property (nonatomic, retain) IBOutlet UIButton* cancelTransferButton; @property (nonatomic, retain) IBOutlet UIProgressView* imageTransferProgressBar; @@ -68,4 +66,6 @@ - (IBAction)onTransferCancelClick:(id)event; - (IBAction)onListTap:(id)sender; +- (void)setChatRoom:(LinphoneChatRoom*)room; + @end diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 7ed6ea3a3..d9d514358 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -32,7 +32,6 @@ @synthesize sendButton; @synthesize messageField; @synthesize editButton; -@synthesize remoteAddress; @synthesize addressLabel; @synthesize composeLabel; @synthesize composeIndicatorView; @@ -73,7 +72,6 @@ [messageField release]; [sendButton release]; [editButton release]; - [remoteAddress release]; [addressLabel release]; [avatarImage release]; [headerView release]; @@ -245,49 +243,32 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - -- (void)setRemoteAddress:(NSString*)aRemoteAddress { - if(remoteAddress != nil) { - [remoteAddress release]; - } - if ([aRemoteAddress hasPrefix:@"sip:"] || [aRemoteAddress hasPrefix:@"sips:"]) { - remoteAddress = [aRemoteAddress copy]; - } else { - char normalizedUserName[256]; - LinphoneCore *lc = [LinphoneManager getLc]; - LinphoneProxyConfig* proxyCfg; - linphone_core_get_default_proxy(lc,&proxyCfg); - LinphoneAddress* linphoneAddress = linphone_address_new(linphone_core_get_identity(lc)); - linphone_proxy_config_normalize_number(proxyCfg, [aRemoteAddress cStringUsingEncoding:[NSString defaultCStringEncoding]], normalizedUserName, sizeof(normalizedUserName)); - linphone_address_set_username(linphoneAddress, normalizedUserName); - remoteAddress = [[NSString stringWithUTF8String:linphone_address_as_string_uri_only(linphoneAddress)] copy]; - linphone_address_destroy(linphoneAddress); - } +- (void)setChatRoom:(LinphoneChatRoom *)room { + self->chatRoom = room; [messageField setText:@""]; - - chatRoom = linphone_core_get_or_create_chat_room([LinphoneManager getLc], [remoteAddress cStringUsingEncoding:[NSString defaultCStringEncoding]]); + [tableController setChatRoom:room]; [self update]; - [tableController setRemoteAddress: remoteAddress]; - [ChatModel readConversation:remoteAddress]; + linphone_chat_room_mark_as_read(chatRoom); [self setComposingVisible:linphone_chat_room_is_remote_composing(chatRoom) withDelay:0]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextReceived object:self]; } - (void)applicationWillEnterForeground:(NSNotification*)notif { - if(remoteAddress != nil) { - [ChatModel readConversation:remoteAddress]; + if(chatRoom != nil) { + linphone_chat_room_mark_as_read(chatRoom); [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextReceived object:self]; } } - (void)update { - if(remoteAddress == NULL) { + if(chatRoom == NULL) { [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat room header: null contact"]; return; } NSString *displayName = nil; UIImage *image = nil; - LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [remoteAddress UTF8String]); + const LinphoneAddress* linphoneAddress = linphone_chat_room_get_peer_address(chatRoom); if (linphoneAddress == NULL) { [[PhoneMainView instance] popCurrentView]; UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address",nil) @@ -308,8 +289,6 @@ static UICompositeViewDescription *compositeDescription = nil; displayName = [FastAddressBook getContactDisplayName:acontact]; image = [FastAddressBook getContactImage:acontact thumbnail:true]; } - [remoteAddress release]; - remoteAddress = [normalizedSipAddress retain]; // Display name if(displayName == nil) { @@ -323,61 +302,33 @@ static UICompositeViewDescription *compositeDescription = nil; } [avatarImage setImage:image]; - linphone_address_destroy(linphoneAddress); } static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { ChatRoomViewController* thiz = (ChatRoomViewController*)ud; - ChatModel *chat = (ChatModel *)linphone_chat_message_get_user_data(msg); + const char*text = linphone_chat_message_get_text(msg); [LinphoneLogger log:LinphoneLoggerLog - format:@"Delivery status for [%@] is [%s]",(chat.message?chat.message:@""),linphone_chat_message_state_to_string(state)]; - [chat setState:[NSNumber numberWithInt:state]]; - [chat update]; - [thiz.tableController updateChatEntry:chat]; - if (state != LinphoneChatMessageStateInProgress) { - linphone_chat_message_set_user_data(msg, NULL); - [chat release]; // no longuer need to keep reference - } - + format:@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)]; + [thiz.tableController updateChatEntry:msg]; } -- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL*)externalUrl withInternalUrl:(NSURL*)internalUrl { +- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL*)externalUrl { if(![LinphoneManager isLcReady]) { [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: Linphone core not ready"]; return FALSE; } - if(remoteAddress == nil) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: Null remoteAddress"]; + if(chatRoom == NULL) { + [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: No chatroom"]; return FALSE; } - if(chatRoom == NULL) { - chatRoom = linphone_core_create_chat_room([LinphoneManager getLc], [remoteAddress UTF8String]); - } - - // Save message in database - ChatModel *chat = [[ChatModel alloc] init]; - [chat setRemoteContact:remoteAddress]; - [chat setLocalContact:@""]; - if(internalUrl == nil) { - [chat setMessage:message]; - } else { - [chat setMessage:[internalUrl absoluteString]]; - } - [chat setDirection:[NSNumber numberWithInt:0]]; - [chat setTime:[NSDate date]]; - [chat setRead:[NSNumber numberWithInt:1]]; - [chat setState:[NSNumber numberWithInt:1]]; //INPROGRESS - [chat create]; - [tableController addChatEntry:chat]; - [tableController scrollToBottom:true]; - [chat release]; LinphoneChatMessage* msg = linphone_chat_room_create_message(chatRoom, [message UTF8String]); - linphone_chat_message_set_user_data(msg, [chat retain]); if(externalUrl) { linphone_chat_message_set_external_body_url(msg, [[externalUrl absoluteString] UTF8String]); } + [tableController addChatEntry:linphone_chat_message_ref(msg)]; linphone_chat_room_send_message2(chatRoom, msg, message_status, self); + [tableController scrollToBottom:true]; return TRUE; } @@ -476,29 +427,31 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (void)textReceivedEvent:(NSNotification *)notif { - //LinphoneChatRoom *room = [[[notif userInfo] objectForKey:@"room"] pointerValue]; - //NSString *message = [[notif userInfo] objectForKey:@"message"]; - LinphoneAddress *from = [[[notif userInfo] objectForKey:@"from"] pointerValue]; - - ChatModel *chat = [[notif userInfo] objectForKey:@"chat"]; + LinphoneAddress * from = [[[notif userInfo] objectForKey:@"from_address"] pointerValue]; + LinphoneChatRoom* room = [[notif.userInfo objectForKey:@"room"] pointerValue]; + LinphoneChatMessage* chat = [[notif.userInfo objectForKey:@"message"] pointerValue]; + if(from == NULL || chat == NULL) { return; } char *fromStr = linphone_address_as_string_uri_only(from); - if(fromStr != NULL) { - if([[NSString stringWithUTF8String:fromStr] - caseInsensitiveCompare:remoteAddress] == NSOrderedSame) { + const LinphoneAddress* cr_from = linphone_chat_room_get_peer_address(chatRoom); + char* cr_from_string = linphone_address_as_string_uri_only(cr_from); + + if(fromStr && cr_from_string ) { + + if(strcasecmp(cr_from_string, fromStr) == 0) { if (![[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)] || [UIApplication sharedApplication].applicationState == UIApplicationStateActive) { - [chat setRead:[NSNumber numberWithInt:1]]; - [chat update]; + linphone_chat_room_mark_as_read(room); [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextReceived object:self]; } [tableController addChatEntry:chat]; [tableController scrollToLastUnread:TRUE]; } - ms_free(fromStr); } + ms_free(fromStr); + ms_free(cr_from_string); } - (void)textComposeEvent:(NSNotification*)notif { @@ -577,7 +530,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (IBAction)onSendClick:(id)event { - if([self sendMessage:[messageField text] withExterlBodyUrl:nil withInternalUrl:nil]) { + if([self sendMessage:[messageField text] withExterlBodyUrl:nil]) { scrollOnGrowingEnabled = FALSE; [messageField setText:@""]; scrollOnGrowingEnabled = TRUE; @@ -673,8 +626,8 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta return FALSE; } -- (void)resendChat:(NSString *)message { - [self sendMessage:message withExterlBodyUrl:nil withInternalUrl:nil]; +- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url { + [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url]]; } #pragma mark ImageSharingDelegate @@ -717,9 +670,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (void)imageSharingUploadDone:(ImageSharing*)aimageSharing url:(NSURL*)url{ - NSURL *imageURL = [aimageSharing userInfo]; - - [self sendMessage:nil withExterlBodyUrl:url withInternalUrl:imageURL]; + [self sendMessage:nil withExterlBodyUrl:url]; [messageView setHidden:FALSE]; [transferView setHidden:TRUE]; @@ -730,7 +681,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [messageView setHidden:FALSE]; [transferView setHidden:TRUE]; - ChatModel *chat = (ChatModel *)[imageSharing userInfo]; + __block LinphoneChatMessage *chat = (LinphoneChatMessage *)[(NSValue*)[imageSharing userInfo] pointerValue]; [[LinphoneManager instance].photoLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){ @@ -747,8 +698,8 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta return; } [LinphoneLogger log:LinphoneLoggerLog format:@"Image saved to [%@]", [assetURL absoluteString]]; - [chat setMessage:[assetURL absoluteString]]; - [chat update]; + linphone_chat_message_set_external_body_url(chat, [[assetURL absoluteString] UTF8String]); + linphone_chat_room_update_url(chatRoom, chat); [tableController updateChatEntry:chat]; }]; imageSharing = nil; diff --git a/Classes/ChatTableViewController.h b/Classes/ChatTableViewController.h index 3c61220fc..3cc3d9e71 100644 --- a/Classes/ChatTableViewController.h +++ b/Classes/ChatTableViewController.h @@ -18,12 +18,10 @@ */ #import +#include "linphone/linphonecore.h" @interface ChatTableViewController : UITableViewController { -@private - NSMutableArray *data; } - (void)loadData; - @end diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index b9de2a41f..0fd427b53 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -26,14 +26,15 @@ #import "UILinphone.h" #import "Utils.h" -@implementation ChatTableViewController +@implementation ChatTableViewController { + @private + MSList* data; +} #pragma mark - Lifecycle Functions - (void)dealloc { - if(data != nil) - [data release]; [super dealloc]; } @@ -49,9 +50,7 @@ #pragma mark - - (void)loadData { - if(data != nil) - [data release]; - data = [[ChatModel listConversations] retain]; + data = linphone_core_get_chat_rooms([LinphoneManager getLc]); [[self tableView] reloadData]; } @@ -62,7 +61,7 @@ } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return [data count]; + return ms_list_size(data); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -78,7 +77,7 @@ [selectedBackgroundView setBackgroundColor:LINPHONE_TABLE_CELL_BACKGROUND_COLOR]; } - [cell setChat:[data objectAtIndex:[indexPath row]]]; + [cell setChatRoom:(LinphoneChatRoom*)ms_list_nth_data(data, [indexPath row])]; return cell; } @@ -88,12 +87,12 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; - ChatModel *chat = [data objectAtIndex:[indexPath row]]; + LinphoneChatRoom *chatRoom = (LinphoneChatRoom*)ms_list_nth_data(data, [indexPath row]); // Go to ChatRoom view ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if(controller != nil) { - [controller setRemoteAddress:[chat remoteContact]]; + [controller setChatRoom:chatRoom]; } } @@ -108,9 +107,12 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if(editingStyle == UITableViewCellEditingStyleDelete) { [tableView beginUpdates]; - ChatModel *chat = [data objectAtIndex:[indexPath row]]; - [ChatModel removeConversation:[chat remoteContact]]; - [data removeObjectAtIndex:[indexPath row]]; + + LinphoneChatRoom *chatRoom = (LinphoneChatRoom*)ms_list_nth_data(data, [indexPath row]); + linphone_chat_room_delete_history(chatRoom); + linphone_chat_room_destroy(chatRoom); + data = linphone_core_get_chat_rooms([LinphoneManager getLc]); + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [tableView endUpdates]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextReceived object:self]; diff --git a/Classes/ChatViewController.m b/Classes/ChatViewController.m index 1bc923dbc..73e3878bd 100644 --- a/Classes/ChatViewController.m +++ b/Classes/ChatViewController.m @@ -20,7 +20,6 @@ #import "ChatViewController.h" #import "PhoneMainView.h" -#import "ChatModel.h" @implementation ChatViewController @synthesize tableController; @@ -113,7 +112,8 @@ static UICompositeViewDescription *compositeDescription = nil; //Push ChatRoom ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if(controller != nil) { - [controller setRemoteAddress:[addressField text]]; + LinphoneChatRoom* room = linphone_core_get_or_create_chat_room([LinphoneManager getLc], [addressField.text UTF8String]); + [controller setChatRoom:room]; } addressField.text = @""; diff --git a/Classes/ContactDetailsTableViewController.m b/Classes/ContactDetailsTableViewController.m index 5b54ce21b..51deecea9 100644 --- a/Classes/ContactDetailsTableViewController.m +++ b/Classes/ContactDetailsTableViewController.m @@ -651,7 +651,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSe [[PhoneMainView instance] popToView:[ChatViewController compositeViewDescription]]; // Got to Chat and push ChatRoom ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if(controller != nil) { - [controller setRemoteAddress:dest]; + LinphoneChatRoom* room = linphone_core_get_or_create_chat_room([LinphoneManager getLc], [dest UTF8String]); + [controller setChatRoom:room]; } } } diff --git a/Classes/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index b23519541..dfaf43580 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -401,7 +401,8 @@ static UICompositeViewDescription *compositeDescription = nil; [[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]]; ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if(controller != nil) { - [controller setRemoteAddress:[NSString stringWithUTF8String:lAddress]]; + LinphoneChatRoom* room = linphone_core_get_or_create_chat_room([LinphoneManager getLc], lAddress); + [controller setChatRoom:room]; } ms_free(lAddress); } diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 224fa59b0..7e385dd6b 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -256,6 +256,20 @@ [self processRemoteNotification:userInfo]; } +- (LinphoneChatRoom*)findChatRoomForContact:(NSString*)contact { + MSList* rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]); + const char* from = [contact UTF8String]; + while (rooms) { + const LinphoneAddress* room_from_address = linphone_chat_room_get_peer_address((LinphoneChatRoom*)rooms->data); + char* room_from = linphone_address_as_string_uri_only(room_from_address); + if( room_from && strcmp(from, room_from)== 0){ + return rooms->data; + } + rooms = rooms->next; + } + return NULL; +} + - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [self fixRing]; @@ -269,13 +283,14 @@ // auto answer only for non-timed local notifications [[LinphoneManager instance] acceptCallForCallId:[notification.userInfo objectForKey:@"callId"]]; } - } else if([notification.userInfo objectForKey:@"chat"] != nil) { - NSString *remoteContact = (NSString*)[notification.userInfo objectForKey:@"chat"]; + } else if([notification.userInfo objectForKey:@"from"] != nil) { + NSString *remoteContact = (NSString*)[notification.userInfo objectForKey:@"from"]; // Go to ChatRoom view [[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]]; ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); if(controller != nil) { - [controller setRemoteAddress:remoteContact]; + LinphoneChatRoom*room = [self findChatRoomForContact:remoteContact]; + [controller setChatRoom:room]; } } else if([notification.userInfo objectForKey:@"callLog"] != nil) { NSString *callLog = (NSString*)[notification.userInfo objectForKey:@"callLog"]; diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 70da8d449..3d1bb38b7 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -128,6 +128,7 @@ typedef struct _LinphoneManagerSounds { + (BOOL)isCodecSupported: (const char*)codecName; + (NSSet *)unsupportedCodecs; + (NSString *)getUserAgent; ++ (int)unreadMessageCount; - (void)resetLinphoneCore; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index e15d3c7db..9ced00f64 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -29,7 +29,6 @@ #import "LinphoneManager.h" #import "LinphoneCoreSettingsStore.h" -#import "ChatModel.h" #include "linphone/linphonecore_utils.h" #include "linphone/lpconfig.h" @@ -76,6 +75,9 @@ extern void libmsbcg729_init(void); #define BACK_CAM_NAME "AV Capture: com.apple.avfoundation.avcapturedevice.built-in_video:0" /*"AV Capture: Back Camera"*/ +NSString *const kLinphoneOldChatDBFilename = @"chat_database.sqlite"; +NSString *const kLinphoneInternalChatDBFilename = @"linphone_chats.db"; + @implementation LinphoneCallAppData - (id)init { if ((self = [super init])) { @@ -261,7 +263,6 @@ struct codec_name_pref_table codec_pref_table[]={ speakerEnabled = FALSE; bluetoothEnabled = FALSE; tunnelMode = FALSE; - [self openDatabase]; [self copyDefaultSettings]; pendindCallIdFromRemoteNotif = [[NSMutableArray alloc] init ]; photoLibrary = [[ALAssetsLibrary alloc] init]; @@ -291,7 +292,6 @@ struct codec_name_pref_table codec_pref_table[]={ } [fastAddressBook release]; - [self closeDatabase]; [logs release]; OSStatus lStatus = AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioRouteChange, audioRouteChangeListenerCallback, self); @@ -311,34 +311,85 @@ struct codec_name_pref_table codec_pref_table[]={ #pragma mark - Database Functions -- (void)openDatabase { - NSString *databasePath = [LinphoneManager documentFile:@"chat_database.sqlite"]; - NSFileManager *filemgr = [NSFileManager defaultManager]; - //[filemgr removeItemAtPath:databasePath error:nil]; - BOOL firstInstall= ![filemgr fileExistsAtPath: databasePath ]; - - if(sqlite3_open([databasePath UTF8String], &database) != SQLITE_OK) { - [LinphoneLogger log:LinphoneLoggerError format:@"Can't open \"%@\" sqlite3 database.", databasePath]; - return; - } - - if (firstInstall) { - char *errMsg; - //better to create the db from the code - const char *sql_stmt = "CREATE TABLE chat (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT NOT NULL, time NUMERIC, read INTEGER, state INTEGER)"; - - if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't create table error[%s] ", errMsg]; - } - } - -} +- (void)migrateChatDBIfNeeded:(LinphoneCore*)lc { + sqlite3* newDb; + char *errMsg; + NSError* error; + NSString *oldDbPath = [LinphoneManager documentFile:kLinphoneOldChatDBFilename]; + NSString *newDbPath = [LinphoneManager documentFile:kLinphoneInternalChatDBFilename]; + BOOL shouldMigrate = [[NSFileManager defaultManager] fileExistsAtPath:oldDbPath]; + LinphoneProxyConfig* default_proxy; + const char* identity = NULL; -- (void)closeDatabase { - if(database != NULL) { - if(sqlite3_close(database) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't close sqlite3 database."]; - } + linphone_core_get_default_proxy(lc, &default_proxy); + + if( !shouldMigrate ) return; + + if( sqlite3_open([newDbPath UTF8String], &newDb) != SQLITE_OK) { + [LinphoneLogger log:LinphoneLoggerError format:@"Can't open \"%@\" sqlite3 database.", newDbPath]; + return; + } + + // attach old database to the new one: + char* attach_stmt = sqlite3_mprintf("ATTACH DATABASE %Q AS oldchats", [oldDbPath UTF8String]); + if( sqlite3_exec(newDb, attach_stmt, NULL, NULL, &errMsg) != SQLITE_OK ){ + [LinphoneLogger logc:LinphoneLoggerError format:"Can't attach old chat table, error[%s] ", errMsg]; + sqlite3_free(errMsg); + goto exit_dbmigration; + } + + + + + // migrate old chats to the new db + const char* migration_statement = "INSERT INTO history (localContact,remoteContact,direction,message,time,read,status) " + "SELECT localContact,remoteContact,direction,message,time,read,state FROM oldchats.chat"; + + if( sqlite3_exec(newDb, migration_statement, NULL, NULL, &errMsg) != SQLITE_OK ){ + [LinphoneLogger logc:LinphoneLoggerError format:"DB migration failed, error[%s] ", errMsg]; + sqlite3_free(errMsg); + goto exit_dbmigration; + } + + // replace empty from: or to: by the current identity. + if( default_proxy ){ + identity = linphone_proxy_config_get_identity(default_proxy); + } + if( !identity ){ + identity = "sip:unknown@sip.linphone.org"; + } + + char* from_conversion = sqlite3_mprintf("UPDATE history SET localContact = %Q WHERE localContact = ''", identity); + if( sqlite3_exec(newDb, from_conversion, NULL, NULL, &errMsg) != SQLITE_OK ){ + [LinphoneLogger logc:LinphoneLoggerError format:"FROM conversion failed, error[%s] ", errMsg]; + sqlite3_free(errMsg); + } + sqlite3_free(from_conversion); + + char* to_conversion = sqlite3_mprintf("UPDATE history SET remoteContact = %Q WHERE remoteContact = ''", identity); + if( sqlite3_exec(newDb, to_conversion, NULL, NULL, &errMsg) != SQLITE_OK ){ + [LinphoneLogger logc:LinphoneLoggerError format:"DB migration failed, error[%s] ", errMsg]; + sqlite3_free(errMsg); + } + sqlite3_free(to_conversion); + + // move already stored images from the messages to the url field + const char* assetslib_migration = "UPDATE history SET url=message, message='' WHERE message LIKE 'assets-library%'"; + if( sqlite3_exec(newDb, assetslib_migration, NULL, NULL, &errMsg) != SQLITE_OK ){ + [LinphoneLogger logc:LinphoneLoggerError format:"Assets-history migration failed, error[%s] ", errMsg]; + sqlite3_free(errMsg); + } + // We will lose received messages with remote url, they will be displayed in plain. We can't do much for them.. + +exit_dbmigration: + + if( attach_stmt ) sqlite3_free(attach_stmt); + + sqlite3_close(newDb); + + // in any case, we should remove the old chat db + if(![[NSFileManager defaultManager] removeItemAtPath:oldDbPath error:&error] ){ + [LinphoneLogger logc:LinphoneLoggerError format:"Could not remove old chat DB: %@", error]; } } @@ -712,10 +763,6 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo #pragma mark - Text Received Functions - (void)onMessageReceived:(LinphoneCore *)lc room:(LinphoneChatRoom *)room message:(LinphoneChatMessage*)msg { - - char *fromStr = linphone_address_as_string_uri_only(linphone_chat_message_get_from(msg)); - if(fromStr == NULL) - return; if (silentPushCompletion) { @@ -726,34 +773,20 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo silentPushCompletion = nil; } - // Save message in database - ChatModel *chat = [[ChatModel alloc] init]; - [chat setLocalContact:@""]; - [chat setRemoteContact:[NSString stringWithUTF8String:fromStr]]; - if (linphone_chat_message_get_external_body_url(msg)) { - [chat setMessage:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(msg)]]; - } else { - [chat setMessage:[NSString stringWithUTF8String:linphone_chat_message_get_text(msg)]]; - } - [chat setDirection:[NSNumber numberWithInt:1]]; - [chat setTime:[NSDate dateWithTimeIntervalSince1970:linphone_chat_message_get_time(msg)]]; - [chat setRead:[NSNumber numberWithInt:0]]; - [chat create]; - - ms_free(fromStr); - - if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)] && [UIApplication sharedApplication].applicationState != UIApplicationStateActive) { - NSString* address = [chat remoteContact]; - NSString *normalizedSipAddress = [FastAddressBook normalizeSipURI:address]; - ABRecordRef contact = [fastAddressBook getContact:normalizedSipAddress]; + const LinphoneAddress* remoteAddress = linphone_chat_message_get_from(msg); + char* c_address = linphone_address_as_string_uri_only(remoteAddress); + NSString* address = [NSString stringWithUTF8String:c_address]; + NSString* from_address = [address copy]; + + ABRecordRef contact = [fastAddressBook getContact:address]; if(contact) { address = [FastAddressBook getContactDisplayName:contact]; } else { if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) { - LinphoneAddress *linphoneAddress = linphone_address_new([normalizedSipAddress cStringUsingEncoding:[NSString defaultCStringEncoding]]); + LinphoneAddress *linphoneAddress = linphone_address_new([address cStringUsingEncoding:[NSString defaultCStringEncoding]]); address = [NSString stringWithUTF8String:linphone_address_get_username(linphoneAddress)]; linphone_address_destroy(linphoneAddress); } @@ -765,26 +798,23 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo // Create a new notification UILocalNotification* notif = [[[UILocalNotification alloc] init] autorelease]; if (notif) { - notif.repeatInterval = 0; - notif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"IM_MSG",nil), address]; - notif.alertAction = NSLocalizedString(@"Show", nil); - notif.soundName = @"msg.caf"; - notif.userInfo = [NSDictionary dictionaryWithObject:[chat remoteContact] forKey:@"chat"]; - + notif.repeatInterval = 0; + notif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"IM_MSG",nil), address]; + notif.alertAction = NSLocalizedString(@"Show", nil); + notif.soundName = @"msg.caf"; + notif.userInfo = @{@"from":from_address }; + [[UIApplication sharedApplication] presentLocalNotificationNow:notif]; } + [from_address release]; } // Post event - NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: - [NSValue valueWithPointer:room], @"room", - [NSValue valueWithPointer:linphone_chat_message_get_from(msg)], @"from", - chat.message, @"message", - chat, @"chat", - nil]; + NSDictionary* dict = @{@"room" :[NSValue valueWithPointer:room], + @"from_address":[NSValue valueWithPointer:linphone_chat_message_get_from(msg)], + @"message" :[NSValue valueWithPointer:msg]}; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextReceived object:self userInfo:dict]; - [chat release]; } static void linphone_iphone_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message) { @@ -995,8 +1025,9 @@ static LinphoneCoreVTable linphonec_vtable = { - (void)finishCoreConfiguration { //get default config from bundle - NSString *zrtpSecretsFileName = [LinphoneManager documentFile:@"zrtp_secrets"]; - const char* lRootCa = [[LinphoneManager bundleFile:@"rootca.pem"] cStringUsingEncoding:[NSString defaultCStringEncoding]]; + NSString *zrtpSecretsFileName = [LinphoneManager documentFile:@"zrtp_secrets"]; + NSString *chatDBFileName = [LinphoneManager documentFile:kLinphoneInternalChatDBFilename]; + const char* lRootCa = [[LinphoneManager bundleFile:@"rootca.pem"] cStringUsingEncoding:[NSString defaultCStringEncoding]]; linphone_core_set_user_agent(theLinphoneCore,"LinphoneIPhone", [[[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)kCFBundleVersionKey] UTF8String]); @@ -1016,6 +1047,9 @@ static LinphoneCoreVTable linphonec_vtable = { linphone_core_set_play_file(theLinphoneCore, lPlay); linphone_core_set_zrtp_secrets_file(theLinphoneCore, [zrtpSecretsFileName cStringUsingEncoding:[NSString defaultCStringEncoding]]); + linphone_core_set_chat_database_path(theLinphoneCore, [chatDBFileName cStringUsingEncoding:[NSString defaultCStringEncoding]]); + + [self migrateChatDBIfNeeded:theLinphoneCore]; [self setupNetworkReachabilityCallback]; @@ -1680,6 +1714,20 @@ static void audioRouteChangeListenerCallback ( return [documentsPath stringByAppendingPathComponent:file]; } ++ (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; + } + return count; +} + + (BOOL)copyFile:(NSString*)src destination:(NSString*)dst override:(BOOL)override { NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; diff --git a/Classes/LinphoneUI/UIChatCell.h b/Classes/LinphoneUI/UIChatCell.h index 49d370c5b..10ae8d29c 100644 --- a/Classes/LinphoneUI/UIChatCell.h +++ b/Classes/LinphoneUI/UIChatCell.h @@ -20,13 +20,13 @@ #import #import "UITransparentTVCell.h" -#import "ChatModel.h" +#include "linphone/linphonecore.h" @interface UIChatCell : UITransparentTVCell { + LinphoneChatRoom* chatRoom; } -@property (nonatomic, retain) ChatModel *chat; @property (nonatomic, retain) IBOutlet UIImageView *avatarImage; @property (nonatomic, retain) IBOutlet UILabel* addressLabel; @property (nonatomic, retain) IBOutlet UILabel* chatContentLabel; @@ -38,4 +38,5 @@ - (IBAction)onDeleteClick:(id)event; +- (void)setChatRoom:(LinphoneChatRoom *)achat; @end diff --git a/Classes/LinphoneUI/UIChatCell.m b/Classes/LinphoneUI/UIChatCell.m index f1604df36..7fe696aef 100644 --- a/Classes/LinphoneUI/UIChatCell.m +++ b/Classes/LinphoneUI/UIChatCell.m @@ -31,7 +31,6 @@ @synthesize unreadMessageLabel; @synthesize unreadMessageView; -@synthesize chat; #pragma mark - Lifecycle Functions @@ -57,24 +56,15 @@ [deleteButton release]; [unreadMessageLabel release]; [unreadMessageView release]; - - [chat release]; - + [super dealloc]; } #pragma mark - Property Funcitons -- (void)setChat:(ChatModel *)achat { - if(chat == achat) - return; - if(chat != nil) { - [chat release]; - } - if(achat) { - chat = [achat retain]; - } +- (void)setChatRoom:(LinphoneChatRoom *)achat { + self->chatRoom = achat; [self update]; } @@ -84,11 +74,12 @@ - (void)update { NSString *displayName = nil; UIImage *image = nil; - if(chat == nil) { + if(chatRoom == nil) { [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat cell: null chat"]; return; } - LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [[chat remoteContact] UTF8String]); + const LinphoneAddress* linphoneAddress = linphone_chat_room_get_peer_address(chatRoom); + if (linphoneAddress == NULL) return; char *tmp = linphone_address_as_string_uri_only(linphoneAddress); @@ -112,28 +103,39 @@ image = [UIImage imageNamed:@"avatar_unknown_small.png"]; } [avatarImage setImage:image]; - - // Message - if([chat isExternalImage] || [chat isInternalImage]) { - [chatContentLabel setText:@""]; - } else { - NSString *message = [chat message]; - // shorten long messages - if([message length] > 50) - message = [[message substringToIndex:50] stringByAppendingString:@"[...]"]; - - [chatContentLabel setText:message]; - } - - int count = [ChatModel unreadMessages:[chat remoteContact]]; - if(count > 0) { - [unreadMessageView setHidden:FALSE]; - [unreadMessageLabel setText:[NSString stringWithFormat:@"%i", count]]; + + MSList* last_message_list = linphone_chat_room_get_history(chatRoom, 1); + LinphoneChatMessage* last_message = last_message_list? last_message_list->data : NULL; + + 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:@""]; + } else { + NSString *message = [NSString stringWithUTF8String:text]; + // shorten long messages + if([message length] > 50) + message = [[message substringToIndex:50] stringByAppendingString:@"[...]"]; + + [chatContentLabel setText:message]; + } + + int count = linphone_chat_room_get_unread_messages_count(chatRoom); + if(count > 0) { + [unreadMessageView setHidden:FALSE]; + [unreadMessageLabel setText:[NSString stringWithFormat:@"%i", count]]; + } else { + [unreadMessageView setHidden:TRUE]; + } } else { + chatContentLabel.text = nil; [unreadMessageView setHidden:TRUE]; } - - linphone_address_destroy(linphoneAddress); + + ms_list_free(last_message_list); } - (void)setEditing:(BOOL)editing { @@ -159,7 +161,7 @@ #pragma mark - Action Functions - (IBAction)onDeleteClick: (id) event { - if(chat != NULL) { + if(chatRoom != NULL) { UIView *view = [self superview]; // Find TableViewCell while( view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview]; diff --git a/Classes/LinphoneUI/UIChatRoomCell.h b/Classes/LinphoneUI/UIChatRoomCell.h index d7cd58e9f..eb7c75d2b 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.h +++ b/Classes/LinphoneUI/UIChatRoomCell.h @@ -19,17 +19,17 @@ #import -#import "ChatModel.h" #import "ChatRoomTableViewController.h" #import "UILoadingImageView.h" #import "UITransparentTVCell.h" #import "UITextViewNoDefine.h" +#include "linphone/linphonecore.h" @interface UIChatRoomCell : UITransparentTVCell { + LinphoneChatMessage* chat; } -@property (nonatomic, retain) ChatModel *chat; @property (nonatomic, retain) IBOutlet UIView *innerView; @property (nonatomic, retain) IBOutlet UIView *bubbleView; @property (nonatomic, retain) IBOutlet UIImageView* backgroundImage; @@ -43,7 +43,7 @@ @property (nonatomic, retain) IBOutlet UITapGestureRecognizer* resendTapGestureRecognizer; - (id)initWithIdentifier:(NSString*)identifier; -+ (CGFloat)height:(ChatModel*)chat width:(int)width; ++ (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width; @property (nonatomic, retain) id chatRoomDelegate; @@ -51,4 +51,6 @@ - (IBAction)onDownloadClick:(id)event; - (IBAction)onImageClick:(id)event; +- (void)setChatMessage:(LinphoneChatMessage*)message; + @end diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index 645fc9d59..99a40eb36 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -37,7 +37,6 @@ @synthesize messageText; @synthesize deleteButton; @synthesize dateLabel; -@synthesize chat; @synthesize statusImage; @synthesize downloadButton; @synthesize chatRoomDelegate; @@ -91,7 +90,6 @@ static UIFont *CELL_FONT = nil; [deleteButton release]; [dateLabel release]; [statusImage release]; - [chat release]; [downloadButton release]; [imageTapGestureRecognizer release]; [resendTapGestureRecognizer release]; @@ -106,17 +104,8 @@ static UIFont *CELL_FONT = nil; #pragma mark - -- (void)setChat:(ChatModel *)achat { - if(chat != achat) { - if(chat != nil) { - [chat release]; - chat = nil; - } - - if(achat != nil) { - chat = [achat retain]; - } - } +- (void)setChatMessage:(LinphoneChatMessage *)message { + self->chat = message; [self update]; } @@ -126,20 +115,23 @@ static UIFont *CELL_FONT = nil; [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat room cell: null chat"]; return; } - - if([chat isExternalImage]) { + 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); + + if(is_external) { [messageText setHidden:TRUE]; - [messageImageView setImage:nil]; [messageImageView setHidden:TRUE]; - [downloadButton setHidden:FALSE]; - } else if([chat isInternalImage]) { + + } else if(url) { + [messageText setHidden:TRUE]; [messageImageView setImage:nil]; [messageImageView startLoading]; - ChatModel *achat = chat; - [[LinphoneManager instance].photoLibrary assetForURL:[NSURL URLWithString:[chat message]] resultBlock:^(ALAsset *asset) { + __block LinphoneChatMessage *achat = chat; + [[LinphoneManager instance].photoLibrary assetForURL:[NSURL URLWithString:[NSString stringWithUTF8String:url]] resultBlock:^(ALAsset *asset) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) { ALAssetRepresentation* representation = [asset defaultRepresentation]; UIImage *image = [UIImage imageWithCGImage:[representation fullResolutionImage] @@ -161,7 +153,7 @@ static UIFont *CELL_FONT = nil; [downloadButton setHidden:TRUE]; } else { [messageText setHidden:FALSE]; - [messageText setText:[chat message]]; + [messageText setText:[NSString stringWithUTF8String:text]]; [messageImageView setImage:nil]; [messageImageView setHidden:TRUE]; @@ -170,20 +162,24 @@ static UIFont *CELL_FONT = nil; } // 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:[chat time]]]; + [dateLabel setText:[dateFormatter stringFromDate:message_date]]; [dateFormatter release]; - if ([chat.state intValue] == LinphoneChatMessageStateInProgress) { + + LinphoneChatMessageState state = linphone_chat_message_get_state(chat); + + if (state== LinphoneChatMessageStateInProgress) { [statusImage setImage:[UIImage imageNamed:@"chat_message_inprogress.png"]]; statusImage.hidden = FALSE; - } else if ([chat.state intValue] == LinphoneChatMessageStateDelivered) { + } else if (state == LinphoneChatMessageStateDelivered) { [statusImage setImage:[UIImage imageNamed:@"chat_message_delivered.png"]]; statusImage.hidden = FALSE; - } else if ([chat.state intValue] == LinphoneChatMessageStateNotDelivered) { + } else if (state == LinphoneChatMessageStateNotDelivered) { [statusImage setImage:[UIImage imageNamed:@"chat_message_not_delivered.png"]]; statusImage.hidden = FALSE; @@ -216,9 +212,12 @@ static UIFont *CELL_FONT = nil; } } -+ (CGSize)viewSize:(ChatModel*)chat width:(int)width { ++ (CGSize)viewSize:(LinphoneChatMessage*)chat width:(int)width { CGSize messageSize; - if(!([chat isExternalImage] || [chat isInternalImage])) { + const char* url = linphone_chat_message_get_external_body_url(chat); + const char* text = linphone_chat_message_get_text(chat); + NSString* messageText = text ? [NSString stringWithUTF8String:text] : @""; + if(url == nil) { if(CELL_FONT == nil) { CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE]; } @@ -226,7 +225,7 @@ static UIFont *CELL_FONT = nil; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7){ - messageSize = [[chat message] + messageSize = [messageText boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName: CELL_FONT} @@ -234,7 +233,7 @@ static UIFont *CELL_FONT = nil; } else #endif { - messageSize = [[chat message] sizeWithFont: CELL_FONT + messageSize = [messageText sizeWithFont: CELL_FONT constrainedToSize: CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f) lineBreakMode: NSLineBreakByTruncatingTail]; } @@ -250,8 +249,8 @@ static UIFont *CELL_FONT = nil; return messageSize; } -+ (CGFloat)height:(ChatModel*)chat width:(int)width { - return [UIChatRoomCell viewSize:chat width:width].height; ++ (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width { + return [UIChatRoomCell viewSize:chatMessage width:width].height; } @@ -262,8 +261,9 @@ static UIFont *CELL_FONT = nil; 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([[chat direction] intValue]) { // Inverted + if(is_outgoing) { // Inverted innerFrame.origin.x = 0.0f; innerFrame.origin.y = 0.0f; } else { @@ -274,7 +274,7 @@ static UIFont *CELL_FONT = nil; CGRect messageFrame = [bubbleView frame]; messageFrame.origin.y = ([innerView frame].size.height - messageFrame.size.height)/2; - if([[chat direction] intValue]) { // Inverted + if(is_outgoing) { // Inverted [backgroundImage setImage:[TUNinePatchCache imageOfSize:[backgroundImage bounds].size forNinePatchNamed:@"chat_bubble_incoming"]]; messageFrame.origin.y += 5; @@ -304,7 +304,9 @@ static UIFont *CELL_FONT = nil; } - (IBAction)onDownloadClick:(id)event { - [chatRoomDelegate chatRoomStartImageDownload:[NSURL URLWithString:chat.message] userInfo:chat]; + NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(chat)]]; + [chatRoomDelegate chatRoomStartImageDownload:url userInfo:[NSValue valueWithPointer:chat]]; + } - (IBAction)onImageClick:(id)event { @@ -317,14 +319,21 @@ static UIFont *CELL_FONT = nil; } - (IBAction)onResendClick:(id)event { - if ([chat.state intValue] == LinphoneChatMessageStateNotDelivered) { - NSString* message = [chat message]; + 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; + [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]; + [chatRoomDelegate resendChat:message withExternalUrl:exturl]; }); } } diff --git a/Classes/LinphoneUI/UIMainBar.m b/Classes/LinphoneUI/UIMainBar.m index 18d750620..899435fab 100644 --- a/Classes/LinphoneUI/UIMainBar.m +++ b/Classes/LinphoneUI/UIMainBar.m @@ -19,7 +19,6 @@ #import "UIMainBar.h" #import "PhoneMainView.h" -#import "ChatModel.h" #import "CAAnimation+Blocks.h" @implementation UIMainBar @@ -243,7 +242,7 @@ static NSString * const kDisappearAnimation = @"disappear"; } - (void)textReceived:(NSNotification*)notif { - [self updateUnreadMessage:[ChatModel unreadMessages] appear:TRUE]; + [self updateUnreadMessage:TRUE]; } @@ -256,10 +255,11 @@ static NSString * const kDisappearAnimation = @"disappear"; } else { [self updateMissedCall:0 appear:TRUE]; } - [self updateUnreadMessage:[ChatModel unreadMessages] appear:appear]; + [self updateUnreadMessage:appear]; } -- (void)updateUnreadMessage:(int)unreadMessage appear:(BOOL)appear{ +- (void)updateUnreadMessage:(BOOL)appear{ + int unreadMessage = [LinphoneManager unreadMessageCount]; if (unreadMessage > 0) { if([chatNotificationView isHidden]) { [chatNotificationView setHidden:FALSE]; diff --git a/Classes/Model/ChatModel.h b/Classes/Model/ChatModel.h deleted file mode 100644 index dad59d221..000000000 --- a/Classes/Model/ChatModel.h +++ /dev/null @@ -1,59 +0,0 @@ -/* ChatModel.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 - - -@interface ChatModel : NSObject { - @private - NSNumber *chatId; - NSString *localContact; - NSString *remoteContact; - NSNumber *direction; //0 outgoing 1 incoming - NSString *message; - NSDate *time; - NSNumber *read; - NSNumber *state; //0 IDLE, 1 in progress, 2 delivered, 3 not delivered see LinphoneChatMessageState -} - -@property (readonly) NSNumber *chatId; -@property (copy) NSString *localContact; -@property (copy) NSString *remoteContact; -@property (copy) NSNumber *direction; -@property (copy) NSString *message; -@property (copy) NSDate *time; -@property (copy) NSNumber *read; -@property (copy) NSNumber *state; - -- (BOOL)isExternalImage; -- (BOOL)isInternalImage; - -- (void)create; -+ (ChatModel*)read:(NSNumber*)id; -- (void)update; -- (void)delete; - -+ (NSMutableArray *)listConversations; -+ (NSMutableArray *)listMessages:(NSString *)contact; -+ (void)removeConversation:(NSString *)contact; -+ (int)unreadMessages; -+ (int)unreadMessages:(NSString *)contact; -+ (void)readConversation:(NSString *)contact; - -@end diff --git a/Classes/Model/ChatModel.m b/Classes/Model/ChatModel.m deleted file mode 100644 index c14e576bf..000000000 --- a/Classes/Model/ChatModel.m +++ /dev/null @@ -1,379 +0,0 @@ -/* ChatModel.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 "ChatModel.h" -#import "LinphoneManager.h" - -@implementation ChatModel - -@synthesize chatId; -@synthesize localContact; -@synthesize remoteContact; -@synthesize message; -@synthesize direction; -@synthesize time; -@synthesize read; -@synthesize state; - -#pragma mark - Lifecycle Functions - -- (id)initWithData:(sqlite3_stmt *)sqlStatement { - self = [super init]; - if (self != nil) { - self->chatId = [[NSNumber alloc] initWithInt: sqlite3_column_int(sqlStatement, 0)]; - self.localContact = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 1)]; - self.remoteContact = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 2)]; - self.direction = [NSNumber numberWithInt:sqlite3_column_int(sqlStatement, 3)]; - self.message = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 4)]; - self.time = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(sqlStatement, 5)]; - self.read = [NSNumber numberWithInt:sqlite3_column_int(sqlStatement, 6)]; - self.state = [NSNumber numberWithInt:sqlite3_column_int(sqlStatement, 7)]; - } - return self; -} - -- (void)dealloc { - [chatId release]; - [localContact release]; - [remoteContact release]; - [message release]; - [direction release]; - [time release]; - [read release]; - [state release]; - [super dealloc]; -} - - -- (BOOL)isExternalImage { - return [message hasPrefix:@"http:"] || [message hasPrefix:@"https:"]; -} - -- (BOOL)isInternalImage { - return [message hasPrefix:@"assets-library:"]; -} - - -#pragma mark - CRUD Functions - -- (void)create { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return; - } - - const char *sql = "INSERT INTO chat (localContact, remoteContact, direction, message, time, read, state) VALUES (@LOCALCONTACT, @REMOTECONTACT, @DIRECTION, @MESSAGE, @TIME, @READ, @STATE)"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [localContact UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_text(sqlStatement, 2, [remoteContact UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_int(sqlStatement, 3, [direction intValue]); - sqlite3_bind_text(sqlStatement, 4, [message UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_double(sqlStatement, 5, [time timeIntervalSince1970]); - sqlite3_bind_int(sqlStatement, 6, [read intValue]); - sqlite3_bind_int(sqlStatement, 7, [state intValue]); - - if (sqlite3_step(sqlStatement) != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - } - - if([self chatId] != nil) { - [chatId release]; - } - chatId = [[NSNumber alloc] initWithInt:(int)sqlite3_last_insert_rowid(database)]; - sqlite3_finalize(sqlStatement); -} - -+ (ChatModel*)read:(NSNumber*)chatId { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return nil; - } - - const char *sql = "SELECT id, localContact, remoteContact, direction, message, time, read FROM chat WHERE id=@ID"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return nil; - } - - // Prepare statement - sqlite3_bind_int(sqlStatement, 1, [chatId intValue]); - - ChatModel* line = nil; - int err = sqlite3_step(sqlStatement); - if (err == SQLITE_ROW) { - line = [[[ChatModel alloc] initWithData:sqlStatement] autorelease]; - } else if (err != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return nil; - } - - sqlite3_finalize(sqlStatement); - return line; -} - -- (void)update { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return; - } - - const char *sql = "UPDATE chat SET localContact=@LOCALCONTACT, remoteContact=@REMOTECONTACT, direction=@DIRECTION, message=@MESSAGE, time=@TIME, read=@READ, state=@STATE WHERE id=@ID"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [localContact UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_text(sqlStatement, 2, [remoteContact UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_int(sqlStatement, 3, [direction intValue]); - sqlite3_bind_text(sqlStatement, 4, [message UTF8String], -1, SQLITE_STATIC); - sqlite3_bind_double(sqlStatement, 5, [time timeIntervalSince1970]); - sqlite3_bind_int(sqlStatement, 6, [read intValue]); - sqlite3_bind_int(sqlStatement, 7, [state intValue]); - sqlite3_bind_int(sqlStatement, 8, [chatId intValue]); - - if (sqlite3_step(sqlStatement) != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return; - } - - sqlite3_finalize(sqlStatement); -} - -- (void)delete { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return; - } - - const char *sql = "DELETE FROM chat WHERE id=@ID"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return; - } - - // Prepare statement - sqlite3_bind_int(sqlStatement, 1, [chatId intValue]); - - if (sqlite3_step(sqlStatement) != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return; - } - - sqlite3_finalize(sqlStatement); -} - - -#pragma mark - - -+ (NSMutableArray *)listConversations { - NSMutableArray *array = [NSMutableArray array]; - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return array; - } - - const char *sql = "SELECT id, localContact, remoteContact, direction, message, time, read, state FROM chat GROUP BY remoteContact ORDER BY time DESC"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return array; - } - - int err; - while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { - ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; - [array addObject:line]; - [line release]; - } - - if (err != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - return array; - } - - sqlite3_finalize(sqlStatement); - - return array; -} - -+ (NSMutableArray *)listMessages:(NSString *)contact { - NSMutableArray *array = [NSMutableArray array]; - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return array; - } - - const char *sql = "SELECT id, localContact, remoteContact, direction, message, time, read, state FROM chat WHERE remoteContact=@REMOTECONTACT ORDER BY time ASC"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return array; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [contact UTF8String], -1, SQLITE_STATIC); - - int err; - while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { - ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; - [array addObject:line]; - [line release]; - } - - if (err != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - return array; - } - - sqlite3_finalize(sqlStatement); - - return array; -} - -+ (void)removeConversation:(NSString *)contact { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return; - } - - const char *sql = "DELETE FROM chat WHERE remoteContact=@REMOTECONTACT"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [contact UTF8String], -1, SQLITE_STATIC); - - if (sqlite3_step(sqlStatement) != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return; - } - - sqlite3_finalize(sqlStatement); -} - -+ (int)unreadMessages { - int count = -1; - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return count; - } - - const char *sql = "SELECT count(*) FROM chat WHERE read=0"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return count; - } - - if (sqlite3_step(sqlStatement) != SQLITE_ROW) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return count; - } - - count = sqlite3_column_int(sqlStatement, 0); - - sqlite3_finalize(sqlStatement); - return count; -} - -+ (int)unreadMessages:(NSString *)contact { - int count = -1; - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return count; - } - - const char *sql = "SELECT count(*) FROM chat WHERE read=0 AND remoteContact=@REMOTECONTACT"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return count; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [contact UTF8String], -1, SQLITE_STATIC); - - if (sqlite3_step(sqlStatement) != SQLITE_ROW) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return count; - } - - count = sqlite3_column_int(sqlStatement, 0); - - sqlite3_finalize(sqlStatement); - return count; -} - -+ (void)readConversation:(NSString *)contact { - sqlite3* database = [[LinphoneManager instance] database]; - if(database == NULL) { - [LinphoneLogger logc:LinphoneLoggerError format:"Database not ready"]; - return; - } - - const char *sql = "UPDATE chat SET read=1 WHERE remoteContact=@REMOTECONTACT"; - sqlite3_stmt *sqlStatement; - if (sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { - [LinphoneLogger logc:LinphoneLoggerError format:"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)]; - return; - } - - // Prepare statement - sqlite3_bind_text(sqlStatement, 1, [contact UTF8String], -1, SQLITE_STATIC); - - if (sqlite3_step(sqlStatement) != SQLITE_DONE) { - [LinphoneLogger logc:LinphoneLoggerError format:"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)]; - sqlite3_finalize(sqlStatement); - return; - } - - sqlite3_finalize(sqlStatement); -} - -@end diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 592b6f7c4..01f66a209 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -219,9 +219,9 @@ static PhoneMainView* phoneMainViewInstance=nil; #pragma mark - Event Functions - (void)textReceived:(NSNotification*)notif { - ChatModel *chat = [[notif userInfo] objectForKey:@"chat"]; - if(chat != nil) { - [self displayMessage:chat]; + LinphoneAddress*from = [[notif.userInfo objectForKey:@"from_address"] pointerValue]; + if(from != nil) { + [self playMessageSound]; } [self updateApplicationBadgeNumber]; } @@ -377,7 +377,7 @@ static PhoneMainView* phoneMainViewInstance=nil; - (void)updateApplicationBadgeNumber { int count = 0; count += linphone_core_get_missed_calls_count([LinphoneManager getLc]); - count += [ChatModel unreadMessages]; + count += [LinphoneManager unreadMessageCount]; count += linphone_core_get_calls_nb([LinphoneManager getLc]); [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count]; } @@ -598,7 +598,7 @@ static PhoneMainView* phoneMainViewInstance=nil; #pragma mark - ActionSheet Functions -- (void)displayMessage:(ChatModel*)chat { +- (void)playMessageSound { if (![[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)] || [UIApplication sharedApplication].applicationState == UIApplicationStateActive) { if(![self removeInhibitedEvent:kLinphoneTextReceived]) {