Wrapper.swift 41 KB

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