Wrapper.swift 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  1. import Foundation
  2. import UIKit
  3. import AVFoundation
  4. public class DcAccounts {
  5. /// The application group identifier defines a group of apps or extensions that have access to a shared container.
  6. /// The ID is created in the apple developer portal and can be changed there.
  7. let applicationGroupIdentifier = "group.chat.delta.ios"
  8. var accountsPointer: OpaquePointer?
  9. public var logger: Logger?
  10. public init() {
  11. }
  12. deinit {
  13. if accountsPointer == nil { return }
  14. dc_accounts_unref(accountsPointer)
  15. accountsPointer = nil
  16. }
  17. public func migrate(dbLocation: String) -> Int {
  18. return Int(dc_accounts_migrate_account(accountsPointer, dbLocation))
  19. }
  20. public func add() -> Int {
  21. return Int(dc_accounts_add_account(accountsPointer))
  22. }
  23. public func get(id: Int) -> DcContext {
  24. let contextPointer = dc_accounts_get_account(accountsPointer, UInt32(id))
  25. return DcContext(contextPointer: contextPointer, logger: logger)
  26. }
  27. public func getAll() -> [Int] {
  28. let cAccounts = dc_accounts_get_all(accountsPointer)
  29. return DcUtils.copyAndFreeArray(inputArray: cAccounts)
  30. }
  31. public func getSelected() -> DcContext {
  32. let cPtr = dc_accounts_get_selected_account(accountsPointer)
  33. return DcContext(contextPointer: cPtr, logger: logger)
  34. }
  35. // call maybeNetwork() from a worker thread.
  36. public func maybeNetwork() {
  37. dc_accounts_maybe_network(accountsPointer)
  38. }
  39. public func maybeNetworkLost() {
  40. dc_accounts_maybe_network_lost(accountsPointer)
  41. }
  42. public func startIo() {
  43. dc_accounts_start_io(accountsPointer)
  44. }
  45. public func stopIo() {
  46. dc_accounts_stop_io(accountsPointer)
  47. }
  48. public func select(id: Int) -> Bool {
  49. return dc_accounts_select_account(accountsPointer, UInt32(id)) == 1
  50. }
  51. public func remove(id: Int) -> Bool {
  52. return dc_accounts_remove_account(accountsPointer, UInt32(id)) == 1
  53. }
  54. public func getEventEmitter() -> DcAccountsEventEmitter {
  55. let eventEmitterPointer = dc_accounts_get_event_emitter(accountsPointer)
  56. return DcAccountsEventEmitter(eventEmitterPointer: eventEmitterPointer)
  57. }
  58. public func openDatabase() {
  59. var version = ""
  60. if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
  61. version += " " + appVersion
  62. }
  63. if var sharedDbLocation = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupIdentifier) {
  64. sharedDbLocation.appendPathComponent("accounts", isDirectory: true)
  65. accountsPointer = dc_accounts_new("iOS\(version)", sharedDbLocation.path)
  66. }
  67. }
  68. public func closeDatabase() {
  69. dc_accounts_unref(accountsPointer)
  70. accountsPointer = nil
  71. }
  72. }
  73. public class DcContext {
  74. public var logger: Logger?
  75. var contextPointer: OpaquePointer?
  76. public var lastErrorString: String?
  77. public var lastWarningString: String = "" // temporary thing to get a grip on some weird errors
  78. public var maxConfigureProgress: Int = 0 // temporary thing to get a grip on some weird errors
  79. public init(contextPointer: OpaquePointer?, logger: Logger?) {
  80. self.contextPointer = contextPointer
  81. self.logger = logger
  82. }
  83. deinit {
  84. if contextPointer == nil { return } // avoid a warning about a "careless call"
  85. dc_context_unref(contextPointer)
  86. contextPointer = nil
  87. }
  88. public var id: Int {
  89. return Int(dc_get_id(contextPointer))
  90. }
  91. // viewType: one of DC_MSG_*
  92. public func newMessage(viewType: Int32) -> DcMsg {
  93. let messagePointer = dc_msg_new(contextPointer, viewType)
  94. return DcMsg(pointer: messagePointer)
  95. }
  96. public func getMessage(id: Int) -> DcMsg {
  97. let messagePointer = dc_get_msg(contextPointer, UInt32(id))
  98. return DcMsg(pointer: messagePointer)
  99. }
  100. public func sendMessage(chatId: Int, message: DcMsg) {
  101. dc_send_msg(contextPointer, UInt32(chatId), message.messagePointer)
  102. }
  103. public func sendVideoChatInvitation(chatId: Int) -> Int {
  104. return Int(dc_send_videochat_invitation(contextPointer, UInt32(chatId)))
  105. }
  106. // TODO: remove count and from parameters if we don't use it
  107. public func getMessageIds(chatId: Int, count: Int? = nil, from: Int? = nil) -> [Int] {
  108. let start = CFAbsoluteTimeGetCurrent()
  109. let cMessageIds = getChatMessages(chatId: chatId)
  110. let diff = CFAbsoluteTimeGetCurrent() - start
  111. logger?.info("⏰ getMessageIds: \(diff) s")
  112. let ids: [Int]
  113. if let from = from {
  114. // skip last part
  115. ids = DcUtils.copyAndFreeArrayWithOffset(inputArray: cMessageIds, len: count, skipEnd: from)
  116. } else if let count = count {
  117. // skip first part
  118. ids = DcUtils.copyAndFreeArrayWithLen(inputArray: cMessageIds, len: count)
  119. } else {
  120. ids = DcUtils.copyAndFreeArray(inputArray: cMessageIds)
  121. }
  122. return ids
  123. }
  124. public func createContact(name: String?, email: String) -> Int {
  125. return Int(dc_create_contact(contextPointer, name, email))
  126. }
  127. public func deleteContact(contactId: Int) -> Bool {
  128. return dc_delete_contact(self.contextPointer, UInt32(contactId)) == 1
  129. }
  130. public func getContacts(flags: Int32, queryString: String? = nil) -> [Int] {
  131. let start = CFAbsoluteTimeGetCurrent()
  132. let cContacts = dc_get_contacts(contextPointer, UInt32(flags), queryString)
  133. let diff = CFAbsoluteTimeGetCurrent() - start
  134. logger?.info("⏰ getContacts: \(diff) s")
  135. return DcUtils.copyAndFreeArray(inputArray: cContacts)
  136. }
  137. public func getContact(id: Int) -> DcContact {
  138. let contactPointer = dc_get_contact(contextPointer, UInt32(id))
  139. return DcContact(contactPointer: contactPointer)
  140. }
  141. public func blockContact(id: Int) {
  142. dc_block_contact(contextPointer, UInt32(id), 1)
  143. }
  144. public func unblockContact(id: Int) {
  145. dc_block_contact(contextPointer, UInt32(id), 0)
  146. }
  147. public func getBlockedContacts() -> [Int] {
  148. let cBlockedContacts = dc_get_blocked_contacts(contextPointer)
  149. return DcUtils.copyAndFreeArray(inputArray: cBlockedContacts)
  150. }
  151. public func addContacts(contactString: String) {
  152. dc_add_address_book(contextPointer, contactString)
  153. }
  154. public func lookupContactIdByAddress(_ address: String) -> Int {
  155. return Int(dc_lookup_contact_id_by_addr(contextPointer, addr))
  156. }
  157. public func acceptChat(chatId: Int) {
  158. dc_accept_chat(contextPointer, UInt32(chatId))
  159. }
  160. public func blockChat(chatId: Int) {
  161. dc_block_chat(contextPointer, UInt32(chatId))
  162. }
  163. public func getChat(chatId: Int) -> DcChat {
  164. let chatPointer = dc_get_chat(contextPointer, UInt32(chatId))
  165. return DcChat(chatPointer: chatPointer)
  166. }
  167. public func getChatIdByContactId(contactId: Int) -> Int {
  168. return Int(dc_get_chat_id_by_contact_id(contextPointer, UInt32(contactId)))
  169. }
  170. public func getChatIdByContactIdOld(_ contactId: Int) -> Int? {
  171. // deprecated function, use getChatIdByContactId() and check for != 0 as for all other places IDs are used
  172. let chatId = dc_get_chat_id_by_contact_id(contextPointer, UInt32(contactId))
  173. if chatId == 0 {
  174. return nil
  175. } else {
  176. return Int(chatId)
  177. }
  178. }
  179. public func getChatlist(flags: Int32, queryString: String?, queryId: Int) -> DcChatlist {
  180. let start = CFAbsoluteTimeGetCurrent()
  181. let chatlistPointer = dc_get_chatlist(contextPointer, flags, queryString, UInt32(queryId))
  182. let chatlist = DcChatlist(chatListPointer: chatlistPointer)
  183. let diff = CFAbsoluteTimeGetCurrent() - start
  184. logger?.info("⏰ getChatlist: \(diff) s")
  185. return chatlist
  186. }
  187. public func sendMsgSync(chatId: Int, msg: DcMsg) {
  188. dc_send_msg_sync(contextPointer, UInt32(chatId), msg.messagePointer)
  189. }
  190. public func getChatMedia(chatId: Int, messageType: Int32, messageType2: Int32, messageType3: Int32) -> [Int] {
  191. guard let messagesPointer = dc_get_chat_media(contextPointer, UInt32(chatId), messageType, messageType2, messageType3) else {
  192. return []
  193. }
  194. let messageIds: [Int] = DcUtils.copyAndFreeArray(inputArray: messagesPointer)
  195. return messageIds
  196. }
  197. @discardableResult
  198. public func createChatByContactId(contactId: Int) -> Int {
  199. return Int(dc_create_chat_by_contact_id(contextPointer, UInt32(contactId)))
  200. }
  201. public func createGroupChat(verified: Bool, name: String) -> Int {
  202. return Int(dc_create_group_chat(contextPointer, verified ? 1 : 0, name))
  203. }
  204. public func addContactToChat(chatId: Int, contactId: Int) -> Bool {
  205. return dc_add_contact_to_chat(contextPointer, UInt32(chatId), UInt32(contactId)) == 1
  206. }
  207. public func removeContactFromChat(chatId: Int, contactId: Int) -> Bool {
  208. return dc_remove_contact_from_chat(contextPointer, UInt32(chatId), UInt32(contactId)) == 1
  209. }
  210. public func setChatName(chatId: Int, name: String) -> Bool {
  211. return dc_set_chat_name(contextPointer, UInt32(chatId), name) == 1
  212. }
  213. public func deleteChat(chatId: Int) {
  214. dc_delete_chat(contextPointer, UInt32(chatId))
  215. }
  216. public func archiveChat(chatId: Int, archive: Bool) {
  217. dc_set_chat_visibility(contextPointer, UInt32(chatId), Int32(archive ? DC_CHAT_VISIBILITY_ARCHIVED : DC_CHAT_VISIBILITY_NORMAL))
  218. }
  219. public func setChatVisibility(chatId: Int, visibility: Int32) {
  220. dc_set_chat_visibility(contextPointer, UInt32(chatId), visibility)
  221. }
  222. public func marknoticedChat(chatId: Int) {
  223. dc_marknoticed_chat(self.contextPointer, UInt32(chatId))
  224. }
  225. public func getSecurejoinQr (chatId: Int) -> String? {
  226. if let cString = dc_get_securejoin_qr(self.contextPointer, UInt32(chatId)) {
  227. let swiftString = String(cString: cString)
  228. dc_str_unref(cString)
  229. return swiftString
  230. }
  231. return nil
  232. }
  233. public func joinSecurejoin (qrCode: String) -> Int {
  234. return Int(dc_join_securejoin(contextPointer, qrCode))
  235. }
  236. public func checkQR(qrCode: String) -> DcLot {
  237. return DcLot(dc_check_qr(contextPointer, qrCode))
  238. }
  239. public func setConfigFromQR(qrCode: String) -> Bool {
  240. return dc_set_config_from_qr(contextPointer, qrCode) != 0
  241. }
  242. public func stopOngoingProcess() {
  243. dc_stop_ongoing_process(contextPointer)
  244. }
  245. public func getInfo() -> String {
  246. if let cString = dc_get_info(contextPointer) {
  247. let info = String(cString: cString)
  248. dc_str_unref(cString)
  249. return info
  250. }
  251. return "ErrGetInfo"
  252. }
  253. public func getContactEncrInfo(contactId: Int) -> String {
  254. if let cString = dc_get_contact_encrinfo(contextPointer, UInt32(contactId)) {
  255. let switftString = String(cString: cString)
  256. dc_str_unref(cString)
  257. return switftString
  258. }
  259. return "ErrGetContactEncrInfo"
  260. }
  261. public func getConnectivity() -> Int32 {
  262. return dc_get_connectivity(contextPointer)
  263. }
  264. public func getConnectivityHtml() -> String {
  265. guard let cString = dc_get_connectivity_html(contextPointer) else { return ""}
  266. let swiftString = String(cString: cString)
  267. dc_str_unref(cString)
  268. return swiftString
  269. }
  270. public func setStockTranslation(id: Int32, localizationKey: String) {
  271. dc_set_stock_translation(contextPointer, UInt32(id), String.localized(localizationKey))
  272. }
  273. public func getDraft(chatId: Int) -> DcMsg? {
  274. if let draft = dc_get_draft(contextPointer, UInt32(chatId)) {
  275. return DcMsg(pointer: draft)
  276. }
  277. return nil
  278. }
  279. public func setDraft(chatId: Int, message: DcMsg?) {
  280. dc_set_draft(contextPointer, UInt32(chatId), message?.messagePointer)
  281. }
  282. public func getFreshMessages() -> DcArray {
  283. return DcArray(arrayPointer: dc_get_fresh_msgs(contextPointer))
  284. }
  285. public func markSeenMessages(messageIds: [UInt32]) {
  286. messageIds.withUnsafeBufferPointer { ptr in
  287. dc_markseen_msgs(contextPointer, ptr.baseAddress, Int32(ptr.count))
  288. }
  289. }
  290. private func getChatMessages(chatId: Int) -> OpaquePointer {
  291. return dc_get_chat_msgs(contextPointer, UInt32(chatId), UInt32(DC_GCM_ADDDAYMARKER), 0)
  292. }
  293. public func getMsgInfo(msgId: Int) -> String {
  294. if let cString = dc_get_msg_info(self.contextPointer, UInt32(msgId)) {
  295. let swiftString = String(cString: cString)
  296. dc_str_unref(cString)
  297. return swiftString
  298. }
  299. return "ErrGetMsgInfo"
  300. }
  301. public func getMsgHtml(msgId: Int) -> String {
  302. guard let cString = dc_get_msg_html(self.contextPointer, UInt32(msgId)) else { return "" }
  303. let swiftString = String(cString: cString)
  304. dc_str_unref(cString)
  305. return swiftString
  306. }
  307. public func deleteMessage(msgId: Int) {
  308. dc_delete_msgs(contextPointer, [UInt32(msgId)], 1)
  309. }
  310. public func deleteMessages(msgIds: [Int]) {
  311. dc_delete_msgs(contextPointer, msgIds.compactMap { UInt32($0) }, Int32(msgIds.count))
  312. }
  313. public func forwardMessage(with msgId: Int, to chat: Int) {
  314. dc_forward_msgs(contextPointer, [UInt32(msgId)], 1, UInt32(chat))
  315. }
  316. public func forwardMessages(with msgIds: [Int], to chat: Int) {
  317. dc_forward_msgs(contextPointer, msgIds.compactMap { UInt32($0) }, Int32(msgIds.count), UInt32(chat))
  318. }
  319. public func sendTextInChat(id: Int, message: String) {
  320. dc_send_text_msg(contextPointer, UInt32(id), message)
  321. }
  322. public func initiateKeyTransfer() -> String? {
  323. if let cString = dc_initiate_key_transfer(self.contextPointer) {
  324. let swiftString = String(cString: cString)
  325. dc_str_unref(cString)
  326. return swiftString
  327. }
  328. return nil
  329. }
  330. public func continueKeyTransfer(msgId: Int, setupCode: String) -> Bool {
  331. return dc_continue_key_transfer(self.contextPointer, UInt32(msgId), setupCode) != 0
  332. }
  333. public func configure() {
  334. maxConfigureProgress = 0
  335. lastWarningString = ""
  336. dc_configure(contextPointer)
  337. }
  338. public func setChatMuteDuration(chatId: Int, duration: Int) {
  339. dc_set_chat_mute_duration(self.contextPointer, UInt32(chatId), Int64(duration))
  340. }
  341. public func setChatEphemeralTimer(chatId: Int, duration: Int) {
  342. dc_set_chat_ephemeral_timer(self.contextPointer, UInt32(chatId), UInt32(duration))
  343. }
  344. public func getChatEphemeralTimer(chatId: Int) -> Int {
  345. return Int(dc_get_chat_ephemeral_timer(self.contextPointer, UInt32(chatId)))
  346. }
  347. public func getConfig(_ key: String) -> String? {
  348. guard let cString = dc_get_config(self.contextPointer, key) else { return nil }
  349. let value = String(cString: cString)
  350. dc_str_unref(cString)
  351. if value.isEmpty {
  352. return nil
  353. }
  354. return value
  355. }
  356. public func setConfig(_ key: String, _ value: String?) {
  357. if let v = value {
  358. dc_set_config(self.contextPointer, key, v)
  359. } else {
  360. dc_set_config(self.contextPointer, key, nil)
  361. }
  362. }
  363. public func getConfigBool(_ key: String) -> Bool {
  364. return strToBool(getConfig(key))
  365. }
  366. public func setConfigBool(_ key: String, _ value: Bool) {
  367. let vStr = value ? "1" : "0"
  368. setConfig(key, vStr)
  369. }
  370. public func getConfigInt(_ key: String) -> Int {
  371. if let str = getConfig(key) {
  372. return Int(str) ?? 0
  373. }
  374. return 0
  375. }
  376. public func setConfigInt(_ key: String, _ value: Int) {
  377. setConfig(key, String(value))
  378. }
  379. public func getUnreadMessages(chatId: Int) -> Int {
  380. return Int(dc_get_fresh_msg_cnt(contextPointer, UInt32(chatId)))
  381. }
  382. public func estimateDeletionCnt(fromServer: Bool, timeout: Int) -> Int {
  383. return Int(dc_estimate_deletion_cnt(contextPointer, fromServer ? 1 : 0, Int64(timeout)))
  384. }
  385. public func isConfigured() -> Bool {
  386. return dc_is_configured(contextPointer) != 0
  387. }
  388. public func getSelfAvatarImage() -> UIImage? {
  389. guard let fileName = selfavatar else { return nil }
  390. let path: URL = URL(fileURLWithPath: fileName, isDirectory: false)
  391. if path.isFileURL {
  392. do {
  393. let data = try Data(contentsOf: path)
  394. return UIImage(data: data)
  395. } catch {
  396. logger?.warning("failed to load image: \(fileName), \(error)")
  397. return nil
  398. }
  399. }
  400. return nil
  401. }
  402. public func setChatProfileImage(chatId: Int, path: String?) {
  403. dc_set_chat_profile_image(contextPointer, UInt32(chatId), path)
  404. }
  405. @discardableResult
  406. public func addDeviceMessage(label: String?, msg: DcMsg) -> Int {
  407. return Int(dc_add_device_msg(contextPointer, label, msg.cptr))
  408. }
  409. public func getProviderFromEmail(addr: String) -> DcProvider? {
  410. guard let dcProviderPointer = dc_provider_new_from_email(contextPointer, addr) else { return nil }
  411. return DcProvider(dcProviderPointer)
  412. }
  413. public func imex(what: Int32, directory: String) {
  414. dc_imex(contextPointer, what, directory, nil)
  415. }
  416. public func imexHasBackup(filePath: String) -> String? {
  417. var file: String?
  418. if let cString = dc_imex_has_backup(contextPointer, filePath) {
  419. file = String(cString: cString)
  420. dc_str_unref(cString)
  421. }
  422. return file
  423. }
  424. public func isSendingLocationsToChat(chatId: Int) -> Bool {
  425. return dc_is_sending_locations_to_chat(contextPointer, UInt32(chatId)) == 1
  426. }
  427. public func sendLocationsToChat(chatId: Int, seconds: Int) {
  428. dc_send_locations_to_chat(contextPointer, UInt32(chatId), Int32(seconds))
  429. }
  430. public func setLocation(latitude: Double, longitude: Double, accuracy: Double) {
  431. dc_set_location(contextPointer, latitude, longitude, accuracy)
  432. }
  433. public func searchMessages(chatId: Int = 0, searchText: String) -> [Int] {
  434. let start = CFAbsoluteTimeGetCurrent()
  435. guard let arrayPointer = dc_search_msgs(contextPointer, UInt32(chatId), searchText) else {
  436. return []
  437. }
  438. let messageIds = DcUtils.copyAndFreeArray(inputArray: arrayPointer)
  439. let diff = CFAbsoluteTimeGetCurrent() - start
  440. logger?.info("⏰ searchMessages: \(diff) s")
  441. return messageIds
  442. }
  443. // also, there is no much worth in adding a separate function or so
  444. // for each config option - esp. if they are just forwarded to the core
  445. // and set/get only at one line of code each.
  446. // this adds a complexity that can be avoided -
  447. // and makes grep harder as these names are typically named following different guidelines.
  448. public var displayname: String? {
  449. get { return getConfig("displayname") }
  450. set { setConfig("displayname", newValue) }
  451. }
  452. public var displaynameAndAddr: String {
  453. var ret = addr ?? ""
  454. if let displayname = displayname {
  455. ret = "\(displayname) (\(ret))"
  456. }
  457. ret += configured ? "" : " (not configured)"
  458. return ret.trimmingCharacters(in: .whitespaces)
  459. }
  460. public var selfstatus: String? {
  461. get { return getConfig("selfstatus") }
  462. set { setConfig("selfstatus", newValue) }
  463. }
  464. public var selfavatar: String? {
  465. get { return getConfig("selfavatar") }
  466. set { setConfig("selfavatar", newValue) }
  467. }
  468. public var addr: String? {
  469. get { return getConfig("addr") }
  470. set { setConfig("addr", newValue) }
  471. }
  472. public var mailServer: String? {
  473. get { return getConfig("mail_server") }
  474. set { setConfig("mail_server", newValue) }
  475. }
  476. public var mailUser: String? {
  477. get { return getConfig("mail_user") }
  478. set { setConfig("mail_user", newValue) }
  479. }
  480. public var mailPw: String? {
  481. get { return getConfig("mail_pw") }
  482. set { setConfig("mail_pw", newValue) }
  483. }
  484. public var mailPort: String? {
  485. get { return getConfig("mail_port") }
  486. set { setConfig("mail_port", newValue) }
  487. }
  488. public var sendServer: String? {
  489. get { return getConfig("send_server") }
  490. set { setConfig("send_server", newValue) }
  491. }
  492. public var sendUser: String? {
  493. get { return getConfig("send_user") }
  494. set { setConfig("send_user", newValue) }
  495. }
  496. public var sendPw: String? {
  497. get { return getConfig("send_pw") }
  498. set { setConfig("send_pw", newValue) }
  499. }
  500. public var sendPort: String? {
  501. get { return getConfig("send_port") }
  502. set { setConfig("send_port", newValue) }
  503. }
  504. public var certificateChecks: Int {
  505. get {
  506. if let str = getConfig("imap_certificate_checks") {
  507. return Int(str) ?? 0
  508. } else {
  509. return 0
  510. }
  511. }
  512. set {
  513. setConfig("smtp_certificate_checks", "\(newValue)")
  514. setConfig("imap_certificate_checks", "\(newValue)")
  515. }
  516. }
  517. private var serverFlags: Int {
  518. // IMAP-/SMTP-flags as a combination of DC_LP flags
  519. get {
  520. if let str = getConfig("server_flags") {
  521. return Int(str) ?? 0
  522. } else {
  523. return 0
  524. }
  525. }
  526. set {
  527. setConfig("server_flags", "\(newValue)")
  528. }
  529. }
  530. public func setAuthFlags(flags: Int) {
  531. var sf = serverFlags
  532. sf = sf & ~0x6 // DC_LP_AUTH_FLAGS
  533. sf = sf | flags
  534. serverFlags = sf
  535. }
  536. public func getAuthFlags() -> Int {
  537. var sf = serverFlags
  538. sf = sf & 0x6 // DC_LP_AUTH_FLAGS
  539. return sf
  540. }
  541. public var e2eeEnabled: Bool {
  542. get { return getConfigBool("e2ee_enabled") }
  543. set { setConfigBool("e2ee_enabled", newValue) }
  544. }
  545. public var mdnsEnabled: Bool {
  546. get { return getConfigBool("mdns_enabled") }
  547. set { setConfigBool("mdns_enabled", newValue) }
  548. }
  549. public var showEmails: Int {
  550. // one of DC_SHOW_EMAILS_*
  551. get { return getConfigInt("show_emails") }
  552. set { setConfigInt("show_emails", newValue) }
  553. }
  554. // do not use. use DcContext::isConfigured() instead
  555. public var configured: Bool {
  556. return getConfigBool("configured")
  557. }
  558. }
  559. public class DcAccountsEventEmitter {
  560. private var eventEmitterPointer: OpaquePointer?
  561. // takes ownership of specified pointer
  562. public init(eventEmitterPointer: OpaquePointer?) {
  563. self.eventEmitterPointer = eventEmitterPointer
  564. }
  565. public func getNextEvent() -> DcEvent? {
  566. guard let eventPointer = dc_accounts_get_next_event(eventEmitterPointer) else { return nil }
  567. return DcEvent(eventPointer: eventPointer)
  568. }
  569. deinit {
  570. dc_accounts_event_emitter_unref(eventEmitterPointer)
  571. }
  572. }
  573. public class DcEvent {
  574. private var eventPointer: OpaquePointer?
  575. // takes ownership of specified pointer
  576. public init(eventPointer: OpaquePointer?) {
  577. self.eventPointer = eventPointer
  578. }
  579. deinit {
  580. dc_event_unref(eventPointer)
  581. }
  582. public var accountId: Int {
  583. return Int(dc_event_get_account_id(eventPointer))
  584. }
  585. public var id: Int32 {
  586. return Int32(dc_event_get_id(eventPointer))
  587. }
  588. public var data1Int: Int {
  589. return Int(dc_event_get_data1_int(eventPointer))
  590. }
  591. public var data2Int: Int {
  592. return Int(dc_event_get_data2_int(eventPointer))
  593. }
  594. public var data2String: String {
  595. guard let cString = dc_event_get_data2_str(eventPointer) else { return "" }
  596. let swiftString = String(cString: cString)
  597. dc_str_unref(cString)
  598. return swiftString
  599. }
  600. }
  601. public class DcChatlist {
  602. private var chatListPointer: OpaquePointer?
  603. // takes ownership of specified pointer
  604. public init(chatListPointer: OpaquePointer?) {
  605. self.chatListPointer = chatListPointer
  606. }
  607. deinit {
  608. dc_chatlist_unref(chatListPointer)
  609. }
  610. public var length: Int {
  611. return dc_chatlist_get_cnt(chatListPointer)
  612. }
  613. public func getChatId(index: Int) -> Int {
  614. return Int(dc_chatlist_get_chat_id(chatListPointer, index))
  615. }
  616. public func getMsgId(index: Int) -> Int {
  617. return Int(dc_chatlist_get_msg_id(chatListPointer, index))
  618. }
  619. public func getSummary(index: Int) -> DcLot {
  620. guard let lotPointer = dc_chatlist_get_summary(self.chatListPointer, index, nil) else {
  621. fatalError("lot-pointer was nil")
  622. }
  623. return DcLot(lotPointer)
  624. }
  625. }
  626. public class DcChat {
  627. var chatPointer: OpaquePointer?
  628. // use DcContext.getChat() instead of calling the constructor directly
  629. public init(chatPointer: OpaquePointer?) {
  630. self.chatPointer = chatPointer
  631. }
  632. deinit {
  633. dc_chat_unref(chatPointer)
  634. }
  635. public var id: Int {
  636. return Int(dc_chat_get_id(chatPointer))
  637. }
  638. public var name: String {
  639. guard let cString = dc_chat_get_name(chatPointer) else { return "" }
  640. let swiftString = String(cString: cString)
  641. dc_str_unref(cString)
  642. return swiftString
  643. }
  644. public var color: UIColor {
  645. return UIColor(netHex: Int(dc_chat_get_color(chatPointer)))
  646. }
  647. public var isArchived: Bool {
  648. return Int(dc_chat_get_visibility(chatPointer)) == DC_CHAT_VISIBILITY_ARCHIVED
  649. }
  650. public var visibility: Int32 {
  651. return dc_chat_get_visibility(chatPointer)
  652. }
  653. public var isUnpromoted: Bool {
  654. return Int(dc_chat_is_unpromoted(chatPointer)) != 0
  655. }
  656. public var isGroup: Bool {
  657. // isMultiUser() might fit better,
  658. // however, would result in lots of code changes, so we leave this as is for now.
  659. let type = Int(dc_chat_get_type(chatPointer))
  660. return type == DC_CHAT_TYPE_GROUP || type == DC_CHAT_TYPE_MAILINGLIST
  661. }
  662. public var isMailinglist: Bool {
  663. return Int(dc_chat_get_type(chatPointer)) == DC_CHAT_TYPE_MAILINGLIST
  664. }
  665. public var isSelfTalk: Bool {
  666. return Int(dc_chat_is_self_talk(chatPointer)) != 0
  667. }
  668. public var isDeviceTalk: Bool {
  669. return Int(dc_chat_is_device_talk(chatPointer)) != 0
  670. }
  671. public var isContactRequest: Bool {
  672. return Int(dc_chat_is_contact_request(chatPointer)) != 0
  673. }
  674. public var canSend: Bool {
  675. return Int(dc_chat_can_send(chatPointer)) != 0
  676. }
  677. public var isProtected: Bool {
  678. return dc_chat_is_protected(chatPointer) != 0
  679. }
  680. public var isMuted: Bool {
  681. return dc_chat_is_muted(chatPointer) != 0
  682. }
  683. public func getContactIds(_ dcContext: DcContext) -> [Int] {
  684. return DcUtils.copyAndFreeArray(inputArray: dc_get_chat_contacts(dcContext.contextPointer, UInt32(id)))
  685. }
  686. public lazy var profileImage: UIImage? = { [weak self] in
  687. guard let cString = dc_chat_get_profile_image(chatPointer) else { return nil }
  688. let filename = String(cString: cString)
  689. dc_str_unref(cString)
  690. let path: URL = URL(fileURLWithPath: filename, isDirectory: false)
  691. if path.isFileURL {
  692. do {
  693. let data = try Data(contentsOf: path)
  694. let image = UIImage(data: data)
  695. return image
  696. } catch {
  697. print("failed to load image: \(filename), \(error)")
  698. return nil
  699. }
  700. }
  701. return nil
  702. }()
  703. public var profileImageURL: URL? {
  704. guard let cString = dc_chat_get_profile_image(chatPointer) else { return nil }
  705. let filename = String(cString: cString)
  706. dc_str_unref(cString)
  707. let path: URL = URL(fileURLWithPath: filename, isDirectory: false)
  708. return path
  709. }
  710. public var isSendingLocations: Bool {
  711. return dc_chat_is_sending_locations(chatPointer) == 1
  712. }
  713. }
  714. public class DcArray {
  715. private var dcArrayPointer: OpaquePointer?
  716. public init(arrayPointer: OpaquePointer) {
  717. dcArrayPointer = arrayPointer
  718. }
  719. deinit {
  720. dc_array_unref(dcArrayPointer)
  721. }
  722. public var count: Int {
  723. return Int(dc_array_get_cnt(dcArrayPointer))
  724. }
  725. }
  726. public class DcMsg {
  727. var messagePointer: OpaquePointer?
  728. init(pointer: OpaquePointer?) {
  729. messagePointer = pointer
  730. }
  731. deinit {
  732. dc_msg_unref(messagePointer)
  733. }
  734. public var cptr: OpaquePointer? {
  735. return messagePointer
  736. }
  737. public lazy var sentDate: Date = {
  738. Date(timeIntervalSince1970: Double(timestamp))
  739. }()
  740. public func formattedSentDate() -> String {
  741. return DateUtils.getExtendedRelativeTimeSpanString(timeStamp: Double(timestamp))
  742. }
  743. public var isForwarded: Bool {
  744. return dc_msg_is_forwarded(messagePointer) != 0
  745. }
  746. public var messageId: String {
  747. return "\(id)"
  748. }
  749. public var id: Int {
  750. return Int(dc_msg_get_id(messagePointer))
  751. }
  752. public var fromContactId: Int {
  753. return Int(dc_msg_get_from_id(messagePointer))
  754. }
  755. public var isFromCurrentSender: Bool {
  756. return fromContactId == DC_CONTACT_ID_SELF
  757. }
  758. public var chatId: Int {
  759. return Int(dc_msg_get_chat_id(messagePointer))
  760. }
  761. public var overrideSenderName: String? {
  762. guard let cString = dc_msg_get_override_sender_name(messagePointer) else { return nil }
  763. let swiftString = String(cString: cString)
  764. dc_str_unref(cString)
  765. return swiftString
  766. }
  767. public func getSenderName(_ dcContact: DcContact, markOverride: Bool = false) -> String {
  768. if let overrideName = overrideSenderName {
  769. return (markOverride ? "~" : "") + overrideName
  770. } else {
  771. return dcContact.displayName
  772. }
  773. }
  774. public var text: String? {
  775. get {
  776. guard let cString = dc_msg_get_text(messagePointer) else { return nil }
  777. let swiftString = String(cString: cString)
  778. dc_str_unref(cString)
  779. return swiftString
  780. }
  781. set {
  782. if let newValue = newValue {
  783. dc_msg_set_text(messagePointer, newValue.cString(using: .utf8))
  784. } else {
  785. dc_msg_set_text(messagePointer, nil)
  786. }
  787. }
  788. }
  789. public var subject: String {
  790. guard let cString = dc_msg_get_subject(messagePointer) else { return "" }
  791. let swiftString = String(cString: cString)
  792. dc_str_unref(cString)
  793. return swiftString
  794. }
  795. public var quoteText: String? {
  796. guard let cString = dc_msg_get_quoted_text(messagePointer) else { return nil }
  797. let swiftString = String(cString: cString)
  798. dc_str_unref(cString)
  799. return swiftString
  800. }
  801. public var quoteMessage: DcMsg? {
  802. get {
  803. guard let msgpointer = dc_msg_get_quoted_msg(messagePointer) else { return nil }
  804. return DcMsg(pointer: msgpointer)
  805. }
  806. set {
  807. if newValue == nil {
  808. fatalError("Quote message cannot be set to null!")
  809. }
  810. dc_msg_set_quote(messagePointer, newValue?.messagePointer)
  811. }
  812. }
  813. public var viewtype: MessageViewType? {
  814. switch dc_msg_get_viewtype(messagePointer) {
  815. case 0:
  816. return nil
  817. case DC_MSG_AUDIO:
  818. return .audio
  819. case DC_MSG_FILE:
  820. return .file
  821. case DC_MSG_GIF:
  822. return .gif
  823. case DC_MSG_TEXT:
  824. return .text
  825. case DC_MSG_IMAGE:
  826. return .image
  827. case DC_MSG_STICKER:
  828. return .image
  829. case DC_MSG_VIDEO:
  830. return .video
  831. case DC_MSG_VOICE:
  832. return .voice
  833. default:
  834. return nil
  835. }
  836. }
  837. public var fileURL: URL? {
  838. if let file = self.file {
  839. return URL(fileURLWithPath: file, isDirectory: false)
  840. }
  841. return nil
  842. }
  843. public lazy var image: UIImage? = { [weak self] in
  844. let filetype = dc_msg_get_viewtype(messagePointer)
  845. if let path = fileURL, filetype == DC_MSG_IMAGE || filetype == DC_MSG_GIF || filetype == DC_MSG_STICKER {
  846. if path.isFileURL {
  847. do {
  848. let data = try Data(contentsOf: path)
  849. let image = UIImage(data: data)
  850. return image
  851. } catch {
  852. print("failed to load image: \(path), \(error)")
  853. return nil
  854. }
  855. }
  856. return nil
  857. } else {
  858. return nil
  859. }
  860. }()
  861. public var messageHeight: CGFloat {
  862. return CGFloat(dc_msg_get_height(messagePointer))
  863. }
  864. public var messageWidth: CGFloat {
  865. return CGFloat(dc_msg_get_width(messagePointer))
  866. }
  867. public var duration: Int {
  868. return Int(dc_msg_get_duration(messagePointer))
  869. }
  870. public func setLateFilingMediaSize(width: CGFloat, height: CGFloat, duration: Int) {
  871. dc_msg_latefiling_mediasize(messagePointer, Int32(width), Int32(height), Int32(duration))
  872. }
  873. public var file: String? {
  874. if let cString = dc_msg_get_file(messagePointer) {
  875. let str = String(cString: cString)
  876. dc_str_unref(cString)
  877. return str.isEmpty ? nil : str
  878. }
  879. return nil
  880. }
  881. public var filemime: String? {
  882. if let cString = dc_msg_get_filemime(messagePointer) {
  883. let str = String(cString: cString)
  884. dc_str_unref(cString)
  885. return str.isEmpty ? nil : str
  886. }
  887. return nil
  888. }
  889. public var filename: String? {
  890. if let cString = dc_msg_get_filename(messagePointer) {
  891. let str = String(cString: cString)
  892. dc_str_unref(cString)
  893. return str.isEmpty ? nil : str
  894. }
  895. return nil
  896. }
  897. public func setFile(filepath: String?, mimeType: String? = nil) {
  898. dc_msg_set_file(messagePointer, filepath, mimeType)
  899. }
  900. public func setDimension(width: CGFloat, height: CGFloat) {
  901. dc_msg_set_dimension(messagePointer, Int32(width), Int32(height))
  902. }
  903. public var filesize: Int {
  904. return Int(dc_msg_get_filebytes(messagePointer))
  905. }
  906. // DC_MSG_*
  907. public var type: Int {
  908. return Int(dc_msg_get_viewtype(messagePointer))
  909. }
  910. // DC_STATE_*
  911. public var state: Int {
  912. return Int(dc_msg_get_state(messagePointer))
  913. }
  914. public var timestamp: Int64 {
  915. return Int64(dc_msg_get_timestamp(messagePointer))
  916. }
  917. public var isInfo: Bool {
  918. return dc_msg_is_info(messagePointer) == 1
  919. }
  920. public var isSetupMessage: Bool {
  921. return dc_msg_is_setupmessage(messagePointer) == 1
  922. }
  923. public var hasHtml: Bool {
  924. return dc_msg_has_html(messagePointer) == 1
  925. }
  926. public var hasLocation: Bool {
  927. return dc_msg_has_location(messagePointer) == 1
  928. }
  929. public var setupCodeBegin: String {
  930. guard let cString = dc_msg_get_setupcodebegin(messagePointer) else { return "" }
  931. let swiftString = String(cString: cString)
  932. dc_str_unref(cString)
  933. return swiftString
  934. }
  935. public func summary(chars: Int) -> String? {
  936. guard let cString = dc_msg_get_summarytext(messagePointer, Int32(chars)) else { return nil }
  937. let swiftString = String(cString: cString)
  938. dc_str_unref(cString)
  939. return swiftString
  940. }
  941. public func summary(chat: DcChat) -> DcLot {
  942. guard let chatPointer = chat.chatPointer else {
  943. fatalError()
  944. }
  945. guard let dcLotPointer = dc_msg_get_summary(messagePointer, chatPointer) else {
  946. fatalError()
  947. }
  948. return DcLot(dcLotPointer)
  949. }
  950. public func showPadlock() -> Bool {
  951. return dc_msg_get_showpadlock(messagePointer) == 1
  952. }
  953. public func getVideoChatUrl() -> String {
  954. guard let cString = dc_msg_get_videochat_url(messagePointer) else { return "" }
  955. let swiftString = String(cString: cString)
  956. dc_str_unref(cString)
  957. return swiftString
  958. }
  959. }
  960. public class DcContact {
  961. private var contactPointer: OpaquePointer?
  962. public init(contactPointer: OpaquePointer?) {
  963. self.contactPointer = contactPointer
  964. }
  965. deinit {
  966. dc_contact_unref(contactPointer)
  967. }
  968. public var displayName: String {
  969. guard let cString = dc_contact_get_display_name(contactPointer) else { return "" }
  970. let swiftString = String(cString: cString)
  971. dc_str_unref(cString)
  972. return swiftString
  973. }
  974. public var nameNAddr: String {
  975. guard let cString = dc_contact_get_name_n_addr(contactPointer) else { return "" }
  976. let swiftString = String(cString: cString)
  977. dc_str_unref(cString)
  978. return swiftString
  979. }
  980. public var editedName: String {
  981. guard let cString = dc_contact_get_name(contactPointer) else { return "" }
  982. let swiftString = String(cString: cString)
  983. dc_str_unref(cString)
  984. return swiftString
  985. }
  986. public var authName: String {
  987. guard let cString = dc_contact_get_auth_name(contactPointer) else { return "" }
  988. let swiftString = String(cString: cString)
  989. dc_str_unref(cString)
  990. return swiftString
  991. }
  992. public var email: String {
  993. guard let cString = dc_contact_get_addr(contactPointer) else { return "" }
  994. let swiftString = String(cString: cString)
  995. dc_str_unref(cString)
  996. return swiftString
  997. }
  998. public var status: String {
  999. guard let cString = dc_contact_get_status(contactPointer) else { return "" }
  1000. let swiftString = String(cString: cString)
  1001. dc_str_unref(cString)
  1002. return swiftString
  1003. }
  1004. public var isVerified: Bool {
  1005. return dc_contact_is_verified(contactPointer) > 0
  1006. }
  1007. public var isBlocked: Bool {
  1008. return dc_contact_is_blocked(contactPointer) == 1
  1009. }
  1010. public lazy var profileImage: UIImage? = { [weak self] in
  1011. guard let cString = dc_contact_get_profile_image(contactPointer) else { return nil }
  1012. let filename = String(cString: cString)
  1013. dc_str_unref(cString)
  1014. let path: URL = URL(fileURLWithPath: filename, isDirectory: false)
  1015. if path.isFileURL {
  1016. do {
  1017. let data = try Data(contentsOf: path)
  1018. return UIImage(data: data)
  1019. } catch {
  1020. print("failed to load image: \(filename), \(error)")
  1021. return nil
  1022. }
  1023. }
  1024. return nil
  1025. }()
  1026. public var profileImageURL: URL? {
  1027. guard let cString = dc_contact_get_profile_image(contactPointer) else { return nil }
  1028. let filename = String(cString: cString)
  1029. dc_str_unref(cString)
  1030. return URL(fileURLWithPath: filename, isDirectory: false)
  1031. }
  1032. public var color: UIColor {
  1033. return UIColor(netHex: Int(dc_contact_get_color(contactPointer)))
  1034. }
  1035. public var id: Int {
  1036. return Int(dc_contact_get_id(contactPointer))
  1037. }
  1038. }
  1039. public class DcLot {
  1040. private var dcLotPointer: OpaquePointer?
  1041. // takes ownership of specified pointer
  1042. public init(_ dcLotPointer: OpaquePointer) {
  1043. self.dcLotPointer = dcLotPointer
  1044. }
  1045. deinit {
  1046. dc_lot_unref(dcLotPointer)
  1047. }
  1048. public var text1: String? {
  1049. guard let cString = dc_lot_get_text1(dcLotPointer) else { return nil }
  1050. let swiftString = String(cString: cString)
  1051. dc_str_unref(cString)
  1052. return swiftString
  1053. }
  1054. public var text1Meaning: Int {
  1055. return Int(dc_lot_get_text1_meaning(dcLotPointer))
  1056. }
  1057. public var text2: String? {
  1058. guard let cString = dc_lot_get_text2(dcLotPointer) else { return nil }
  1059. let swiftString = String(cString: cString)
  1060. dc_str_unref(cString)
  1061. return swiftString
  1062. }
  1063. public var timestamp: Int64 {
  1064. return Int64(dc_lot_get_timestamp(dcLotPointer))
  1065. }
  1066. public var state: Int {
  1067. return Int(dc_lot_get_state(dcLotPointer))
  1068. }
  1069. public var id: Int {
  1070. return Int(dc_lot_get_id(dcLotPointer))
  1071. }
  1072. }
  1073. public class DcProvider {
  1074. private var dcProviderPointer: OpaquePointer?
  1075. // takes ownership of specified pointer
  1076. public init(_ dcProviderPointer: OpaquePointer) {
  1077. self.dcProviderPointer = dcProviderPointer
  1078. }
  1079. deinit {
  1080. dc_provider_unref(dcProviderPointer)
  1081. }
  1082. public var status: Int {
  1083. return Int(dc_provider_get_status(dcProviderPointer))
  1084. }
  1085. public var beforeLoginHint: String {
  1086. guard let cString = dc_provider_get_before_login_hint(dcProviderPointer) else { return "" }
  1087. let swiftString = String(cString: cString)
  1088. dc_str_unref(cString)
  1089. return swiftString
  1090. }
  1091. public var getOverviewPage: String {
  1092. guard let cString = dc_provider_get_overview_page(dcProviderPointer) else { return "" }
  1093. let swiftString = String(cString: cString)
  1094. dc_str_unref(cString)
  1095. return swiftString
  1096. }
  1097. }
  1098. public enum MessageViewType: CustomStringConvertible {
  1099. case audio
  1100. case file
  1101. case gif
  1102. case image
  1103. case text
  1104. case video
  1105. case voice
  1106. public var description: String {
  1107. switch self {
  1108. // Use Internationalization, as appropriate.
  1109. case .audio: return "Audio"
  1110. case .file: return "File"
  1111. case .gif: return "GIF"
  1112. case .image: return "Image"
  1113. case .text: return "Text"
  1114. case .video: return "Video"
  1115. case .voice: return "Voice"
  1116. }
  1117. }
  1118. }
  1119. func strToBool(_ value: String?) -> Bool {
  1120. if let vStr = value {
  1121. if let vInt = Int(vStr) {
  1122. return vInt == 1
  1123. }
  1124. return false
  1125. }
  1126. return false
  1127. }