blob: b825344a1b3fe529e1d64f1e5461f0e85bf118d6 [file] [log] [blame]
Olivier Soldanod4311552017-11-20 15:09:53 -05001/*
Sébastien Blin029ffa82019-01-02 17:43:48 -05002 * Copyright (C) 2017-2019 Savoir-faire Linux Inc.
Olivier Soldanod4311552017-11-20 15:09:53 -05003 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
Andreas Traczyk77a50d52018-05-08 17:47:31 -040020#import <map>
21
Olivier Soldanod4311552017-11-20 15:09:53 -050022#import <Foundation/Foundation.h>
Andreas Traczyk252a94a2018-04-20 16:36:20 -040023#import "NSString+Extensions.h"
Kateryna Kostiuk9fca5422018-11-19 16:27:46 -050024#import "views/NSColor+RingTheme.h"
25
Andreas Traczyk77a50d52018-05-08 17:47:31 -040026
27// new lrc
Olivier Soldanod4311552017-11-20 15:09:53 -050028#import <api/conversation.h>
29#import <api/conversationmodel.h>
30#import <api/account.h>
31#import <api/contactmodel.h>
32#import <api/contact.h>
Andreas Traczyk77a50d52018-05-08 17:47:31 -040033
Kateryna Kostiuk0c0801e2019-07-18 20:10:51 -040034//Qt
35#import <QtCore/QDir>
36#import <qapplication.h>
37
Olivier Soldanod4311552017-11-20 15:09:53 -050038static inline NSString* bestIDForConversation(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model)
39{
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040040 try {
41 auto contact = model.owner.contactModel->getContact(conv.participants[0]);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040042 auto name = contact.registeredName.trimmed().replace("\r","").replace("\n","");
43 if (!name.isEmpty()) {
44 return [name.toNSString() removeEmptyLinesAtBorders];
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040045 }
46 else {
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040047 return [contact.profileInfo.uri.trimmed().replace("\r","").replace("\n","").toNSString() removeEmptyLinesAtBorders];
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040048 }
49 } catch (std::out_of_range& e) {
50 NSLog(@"bestIDForConversation: getContact - out of range");
Kateryna Kostiuk4c703872018-12-28 17:29:05 -050051 return @"";
Andreas Traczyk252a94a2018-04-20 16:36:20 -040052 }
Olivier Soldanod4311552017-11-20 15:09:53 -050053}
54
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040055static inline NSString* bestIDForAccount(const lrc::api::account::Info& account)
56{
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040057 auto name = account.registeredName.trimmed().replace("\r","").replace("\n","");
58 if (!name.isEmpty()) {
59 return [name.toNSString() removeEmptyLinesAtBorders];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040060 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040061 return [account.profileInfo.uri.trimmed().replace("\r","").replace("\n","").toNSString() removeEmptyLinesAtBorders];
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040062}
63
64static inline NSString* bestNameForAccount(const lrc::api::account::Info& account)
65{
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040066 if (account.profileInfo.alias.isEmpty()) {
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040067 return bestIDForAccount(account);
68 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040069 return account.profileInfo.alias.toNSString();
Kateryna Kostiukd73f9602018-07-24 13:51:28 -040070}
71
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040072static inline NSString* bestIDForContact(const lrc::api::contact::Info& contact)
73{
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040074 auto name = contact.registeredName.trimmed().replace("\r","").replace("\n","");
75 if (!name.isEmpty()) {
76 return [name.toNSString() removeEmptyLinesAtBorders];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040077 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040078 return [contact.profileInfo.uri.trimmed().replace("\r","").replace("\n","").toNSString() removeEmptyLinesAtBorders];
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040079}
80
81static inline NSString* bestNameForContact(const lrc::api::contact::Info& contact)
82{
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040083 if (contact.profileInfo.alias.isEmpty()) {
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040084 return bestIDForContact(contact);
85 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040086 return contact.profileInfo.alias.toNSString();
Kateryna Kostiuk1f8c1252018-07-30 18:18:57 -040087}
88
Olivier Soldanod4311552017-11-20 15:09:53 -050089static inline NSString* bestNameForConversation(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model)
90{
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040091 try {
92 auto contact = model.owner.contactModel->getContact(conv.participants[0]);
Kateryna Kostiukc867eb92020-03-08 13:15:17 -040093 if (contact.profileInfo.alias.isEmpty()) {
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040094 return bestIDForConversation(conv, model);
95 }
96 auto alias = contact.profileInfo.alias;
Andreas Traczyk4e39aa52018-05-11 17:29:26 -040097 if(alias.length() == 0) {
98 return bestIDForConversation(conv, model);
99 }
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400100 return [alias.toNSString() removeEmptyLinesAtBorders];
Andreas Traczyk4e39aa52018-05-11 17:29:26 -0400101 } catch (std::out_of_range& e) {
102 NSLog(@"bestNameForConversation: getContact - out of range");
Kateryna Kostiuk4c703872018-12-28 17:29:05 -0500103 return @"";
Andreas Traczyk252a94a2018-04-20 16:36:20 -0400104 }
Andreas Traczyk252a94a2018-04-20 16:36:20 -0400105}
106
Kateryna Kostiuk0c0801e2019-07-18 20:10:51 -0400107static inline NSString* defaultRingtonePath() {
108 QDir ringtonesDir(QCoreApplication::applicationDirPath());
109 ringtonesDir.cdUp();
110 ringtonesDir.cd("Resources/ringtones/");
111 return [ringtonesDir.path().toNSString() stringByAppendingString:@"/default.opus"];
112}
113
Andreas Traczyk252a94a2018-04-20 16:36:20 -0400114static inline lrc::api::profile::Type profileType(const lrc::api::conversation::Info& conv, const lrc::api::ConversationModel& model)
115{
116 @try {
117 auto contact = model.owner.contactModel->getContact(conv.participants[0]);
118 return contact.profileInfo.type;
119 }
120 @catch (NSException *exception) {
121 lrc::api::profile::Type::INVALID;
122 }
Olivier Soldanod4311552017-11-20 15:09:53 -0500123}
Anthony Léonard6f819752018-01-05 09:53:40 -0500124
125/**
126 * This function return an iterator pointing to a Conversation::Info in ConversationModel given its uid. If not found
127 * the iterator is invalid thus it needs to be checked by caller.
128 * @param uid UID of conversation being searched
129 * @param model ConversationModel in which to do the lookup
Kateryna Kostiuk146cb9e2020-08-11 14:29:26 -0400130 * @param includeSearchResult include search result
Anthony Léonard6f819752018-01-05 09:53:40 -0500131 * @return iterator pointing to corresponding Conversation if any. Points to past-the-end element otherwise.
132 */
Kateryna Kostiuk146cb9e2020-08-11 14:29:26 -0400133static inline lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromUid(const QString& uid, const lrc::api::ConversationModel& model, bool includeSearchResult) {
134 auto result = std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(),
Anthony Léonard6f819752018-01-05 09:53:40 -0500135 [&] (const lrc::api::conversation::Info& conv) {
136 return uid == conv.uid;
137 });
Kateryna Kostiuk146cb9e2020-08-11 14:29:26 -0400138 if (!includeSearchResult || (result != model.allFilteredConversations().end())) {
139 return result;
140 }
141 return std::find_if(model.getAllSearchResults().begin(), model.getAllSearchResults().end(),
142 [&] (const lrc::api::conversation::Info& conv) {
143 return uid == conv.uid;
144 });
145}
146
147/**
148 * This function true if conversation exists
149 * the iterator is invalid thus it needs to be checked by caller.
150 * @param conversation iterator pointing to a Conversation::Info in ConversationModel
151 * @param model ConversationModel in which to do the lookup
152 * @param includeSearchResult include search result
153 * @return iterator pointing to corresponding Conversation if any. Points to past-the-end element otherwise.
154 */
155static inline bool conversationExists(lrc::api::ConversationModel::ConversationQueue::const_iterator conversation, const lrc::api::ConversationModel& model, bool includeSearchResult) {
156 return includeSearchResult ? (conversation != model.allFilteredConversations().end() || conversation != model.getAllSearchResults().end()) : conversation != model.allFilteredConversations().end();
Anthony Léonard6f819752018-01-05 09:53:40 -0500157}
Andreas Traczyk77a50d52018-05-08 17:47:31 -0400158
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500159/**
160 * This function return an iterator pointing to a Conversation::Info in ConversationModel given its participant uri. Will not work for group chat.
161 * @param uri URI of participant
162 * @param model ConversationModel in which to do the lookup
163 * @return iterator pointing to corresponding Conversation if any. Points to past-the-end element otherwise.
164 */
Kateryna Kostiukc867eb92020-03-08 13:15:17 -0400165static inline lrc::api::ConversationModel::ConversationQueue::const_iterator getConversationFromURI(const QString& uri, const lrc::api::ConversationModel& model) {
Kateryna Kostiuke3503842018-12-12 16:39:45 -0500166 return std::find_if(model.allFilteredConversations().begin(), model.allFilteredConversations().end(),
167 [&] (const lrc::api::conversation::Info& conv) {
168 return uri == conv.participants[0];
169 });
170}
171
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400172static inline bool isUrlAccessibleFromSandbox(NSURL* url)
173{
174 NSFileManager* fileManager = [[NSFileManager alloc] init];
175 NSArray* urlPathsMusic = [fileManager URLsForDirectory:NSMusicDirectory
176 inDomains:NSUserDomainMask];
177 NSArray* urlPathsPictures = [fileManager URLsForDirectory:NSPicturesDirectory
178 inDomains:NSUserDomainMask];
179 NSArray* urlPathsDownloads = [fileManager URLsForDirectory:NSDownloadsDirectory
180 inDomains:NSUserDomainMask];
181 NSArray* urlPathsMovies = [fileManager URLsForDirectory:NSMoviesDirectory
182 inDomains:NSUserDomainMask];
183 NSArray* availablePaths = [[[urlPathsMusic arrayByAddingObjectsFromArray: urlPathsPictures] arrayByAddingObjectsFromArray: urlPathsDownloads] arrayByAddingObjectsFromArray: urlPathsMovies];
184 if([availablePaths containsObject:url]) {
185 return YES;
186 }
187 for (NSURL* availableUrl in availablePaths) {
188 if ([url.path containsString:availableUrl.path]) {
189 return YES;
190 }
191 }
192 return NO;
193}
194
195static inline bool appSandboxed()
196{
197 NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
Kateryna Kostiukb88d27f2018-06-14 12:56:52 -0400198 NSString* url = [[NSURL fileURLWithPath:NSHomeDirectory()] path];
199 NSString* appPath = [@"Library/Containers/" stringByAppendingString:bundleID];
200 if ([url containsString: appPath]) {
Kateryna Kostiuk4138db12018-06-08 15:52:18 -0400201 return YES;
202 }
203 return NO;
204}
Kateryna Kostiuk9fca5422018-11-19 16:27:46 -0500205
206static inline NSColor* colorForAccountStatus(const lrc::api::account::Status status)
207{
208 NSColor *accountStatusColor = [NSColor unregisteredColor];
209 switch (status) {
210 case lrc::api::account::Status::REGISTERED:
211 accountStatusColor = [NSColor presenceColor];
212 break;
213 case lrc::api::account::Status::TRYING:
214 accountStatusColor = [NSColor orangeColor];
215 break;
216 default:
217 break;
218 }
219 return accountStatusColor;
220}