Wrapper.swift 45 KB

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