Wrapper.swift 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  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 init() {
  10. }
  11. deinit {
  12. if accountsPointer == nil { return }
  13. dc_accounts_unref(accountsPointer)
  14. accountsPointer = nil
  15. }
  16. public func migrateAccount(dbLocation: String) -> Int {
  17. return Int(dc_accounts_migrate_account(accountsPointer, dbLocation))
  18. }
  19. public func addAccount() -> Int {
  20. return Int(dc_accounts_add_account(accountsPointer))
  21. }
  22. public func getAccount(id: Int) -> DcContext {
  23. let contextPointer = dc_accounts_get_account(accountsPointer, UInt32(id))
  24. return DcContext(contextPointer: contextPointer)
  25. }
  26. public func getAll() -> [Int] {
  27. let cAccounts = dc_accounts_get_all(accountsPointer)
  28. return DcUtils.copyAndFreeArray(inputArray: cAccounts)
  29. }
  30. public func get() -> DcContext {
  31. let cPtr = dc_accounts_get_selected_account(accountsPointer)
  32. return DcContext(contextPointer: cPtr)
  33. }
  34. // call maybeNetwork() from a worker thread.
  35. public func maybeNetwork() {
  36. dc_accounts_maybe_network(accountsPointer)
  37. }
  38. public func maybeStartIo() {
  39. if get().isConfigured() {
  40. dc_accounts_start_io(accountsPointer)
  41. }
  42. }
  43. public func stopIo() {
  44. dc_accounts_stop_io(accountsPointer)
  45. }
  46. public func selectAccount(id: Int) -> Bool {
  47. return dc_accounts_select_account(accountsPointer, UInt32(id)) == 1
  48. }
  49. public func removeAccount(id: Int) -> Bool {
  50. return dc_accounts_remove_account(accountsPointer, UInt32(id)) == 1
  51. }
  52. public func importAccount(filePath: String) -> Int {
  53. return Int(dc_accounts_import_account(accountsPointer, filePath))
  54. }
  55. public func getEventEmitter() -> DcAccountsEventEmitter {
  56. let eventEmitterPointer = dc_accounts_get_event_emitter(accountsPointer)
  57. return DcAccountsEventEmitter(eventEmitterPointer: eventEmitterPointer)
  58. }
  59. public func openDatabase() {
  60. var version = ""
  61. if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
  62. version += " " + appVersion
  63. }
  64. if var sharedDbLocation = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: applicationGroupIdentifier) {
  65. sharedDbLocation.appendPathComponent("accounts", isDirectory: true)
  66. accountsPointer = dc_accounts_new("iOS\(version)", sharedDbLocation.path)
  67. }
  68. }
  69. public func closeDatabase() {
  70. dc_accounts_unref(accountsPointer)
  71. accountsPointer = nil
  72. }
  73. }
  74. public class DcContext {
  75. public var logger: Logger?
  76. var contextPointer: OpaquePointer?
  77. public var lastErrorString: String?
  78. public var lastWarningString: String = "" // temporary thing to get a grip on some weird errors
  79. public var maxConfigureProgress: Int = 0 // temporary thing to get a grip on some weird errors
  80. public init() {
  81. }
  82. public init(contextPointer: OpaquePointer?) {
  83. self.contextPointer = contextPointer
  84. }
  85. deinit {
  86. if contextPointer == nil { return } // avoid a warning about a "careless call"
  87. dc_context_unref(contextPointer)
  88. contextPointer = nil
  89. }
  90. public var id: Int {
  91. return Int(dc_get_id(contextPointer))
  92. }
  93. // viewType: one of DC_MSG_*
  94. public func newMessage(viewType: Int32) -> DcMsg {
  95. let messagePointer = dc_msg_new(contextPointer, viewType)
  96. return DcMsg(pointer: messagePointer)
  97. }
  98. public func getMessage(id: Int) -> DcMsg {
  99. let messagePointer = dc_get_msg(contextPointer, UInt32(id))
  100. return DcMsg(pointer: messagePointer)
  101. }
  102. public func sendMessage(chatId: Int, message: DcMsg) {
  103. dc_send_msg(contextPointer, UInt32(chatId), message.messagePointer)
  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 getChat(chatId: Int) -> DcChat {
  154. let chatPointer = dc_get_chat(contextPointer, UInt32(chatId))
  155. return DcChat(chatPointer: chatPointer)
  156. }
  157. public func getChatIdByContactId(contactId: Int) -> Int {
  158. return Int(dc_get_chat_id_by_contact_id(contextPointer, UInt32(contactId)))
  159. }
  160. public func getChatIdByContactIdOld(_ contactId: Int) -> Int? {
  161. // deprecated function, use getChatIdByContactId() and check for != 0 as for all other places IDs are used
  162. let chatId = dc_get_chat_id_by_contact_id(contextPointer, UInt32(contactId))
  163. if chatId == 0 {
  164. return nil
  165. } else {
  166. return Int(chatId)
  167. }
  168. }
  169. @discardableResult
  170. public func decideOnContactRequest(_ messageId: Int, _ decision: Int32) -> DcChat {
  171. let chatId = dc_decide_on_contact_request(contextPointer, UInt32(messageId), decision)
  172. return getChat(chatId: Int(chatId))
  173. }
  174. public func getChatlist(flags: Int32, queryString: String?, queryId: Int) -> DcChatlist {
  175. let start = CFAbsoluteTimeGetCurrent()
  176. let chatlistPointer = dc_get_chatlist(contextPointer, flags, queryString, UInt32(queryId))
  177. let chatlist = DcChatlist(chatListPointer: chatlistPointer)
  178. let diff = CFAbsoluteTimeGetCurrent() - start
  179. logger?.info("⏰ getChatlist: \(diff) s")
  180. return chatlist
  181. }
  182. public func sendMsgSync(chatId: Int, msg: DcMsg) {
  183. dc_send_msg_sync(contextPointer, UInt32(chatId), msg.messagePointer)
  184. }
  185. public func getChatMedia(chatId: Int, messageType: Int32, messageType2: Int32, messageType3: Int32) -> [Int] {
  186. guard let messagesPointer = dc_get_chat_media(contextPointer, UInt32(chatId), messageType, messageType2, messageType3) else {
  187. return []
  188. }
  189. let messageIds: [Int] = DcUtils.copyAndFreeArray(inputArray: messagesPointer)
  190. return messageIds
  191. }
  192. @discardableResult
  193. public func createChatByContactId(contactId: Int) -> Int {
  194. return Int(dc_create_chat_by_contact_id(contextPointer, UInt32(contactId)))
  195. }
  196. public func createGroupChat(verified: Bool, name: String) -> Int {
  197. return Int(dc_create_group_chat(contextPointer, verified ? 1 : 0, name))
  198. }
  199. public func addContactToChat(chatId: Int, contactId: Int) -> Bool {
  200. return dc_add_contact_to_chat(contextPointer, UInt32(chatId), UInt32(contactId)) == 1
  201. }
  202. public func removeContactFromChat(chatId: Int, contactId: Int) -> Bool {
  203. return dc_remove_contact_from_chat(contextPointer, UInt32(chatId), UInt32(contactId)) == 1
  204. }
  205. public func setChatName(chatId: Int, name: String) -> Bool {
  206. return dc_set_chat_name(contextPointer, UInt32(chatId), name) == 1
  207. }
  208. public func deleteChat(chatId: Int) {
  209. dc_delete_chat(contextPointer, UInt32(chatId))
  210. }
  211. public func archiveChat(chatId: Int, archive: Bool) {
  212. dc_set_chat_visibility(contextPointer, UInt32(chatId), Int32(archive ? DC_CHAT_VISIBILITY_ARCHIVED : DC_CHAT_VISIBILITY_NORMAL))
  213. }
  214. public func setChatVisibility(chatId: Int, visibility: Int32) {
  215. dc_set_chat_visibility(contextPointer, UInt32(chatId), visibility)
  216. }
  217. public func marknoticedChat(chatId: Int) {
  218. dc_marknoticed_chat(self.contextPointer, UInt32(chatId))
  219. }
  220. public func getSecurejoinQr (chatId: Int) -> String? {
  221. if let cString = dc_get_securejoin_qr(self.contextPointer, UInt32(chatId)) {
  222. let swiftString = String(cString: cString)
  223. dc_str_unref(cString)
  224. return swiftString
  225. }
  226. return nil
  227. }
  228. public func joinSecurejoin (qrCode: String) -> Int {
  229. return Int(dc_join_securejoin(contextPointer, qrCode))
  230. }
  231. public func checkQR(qrCode: String) -> DcLot {
  232. return DcLot(dc_check_qr(contextPointer, qrCode))
  233. }
  234. public func setConfigFromQR(qrCode: String) -> Bool {
  235. return dc_set_config_from_qr(contextPointer, qrCode) != 0
  236. }
  237. public func stopOngoingProcess() {
  238. dc_stop_ongoing_process(contextPointer)
  239. }
  240. public func getInfo() -> String {
  241. if let cString = dc_get_info(contextPointer) {
  242. let info = String(cString: cString)
  243. dc_str_unref(cString)
  244. return info
  245. }
  246. return "ErrGetInfo"
  247. }
  248. public func getContactEncrInfo(contactId: Int) -> String {
  249. if let cString = dc_get_contact_encrinfo(contextPointer, UInt32(contactId)) {
  250. let switftString = String(cString: cString)
  251. dc_str_unref(cString)
  252. return switftString
  253. }
  254. return "ErrGetContactEncrInfo"
  255. }
  256. public func openDatabase(dbFile: String) {
  257. var version = ""
  258. if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
  259. version += " " + appVersion
  260. }
  261. contextPointer = dc_context_new("iOS" + version, dbFile, nil)
  262. }
  263. public func closeDatabase() {
  264. dc_context_unref(contextPointer)
  265. contextPointer = nil
  266. }
  267. public func setStockTranslation(id: Int32, localizationKey: String) {
  268. dc_set_stock_translation(contextPointer, UInt32(id), String.localized(localizationKey))
  269. }
  270. public func getDraft(chatId: Int) -> DcMsg? {
  271. if let draft = dc_get_draft(contextPointer, UInt32(chatId)) {
  272. return DcMsg(pointer: draft)
  273. }
  274. return nil
  275. }
  276. public func setDraft(chatId: Int, message: DcMsg?) {
  277. dc_set_draft(contextPointer, UInt32(chatId), message?.messagePointer)
  278. }
  279. public func getFreshMessages() -> DcArray {
  280. return DcArray(arrayPointer: dc_get_fresh_msgs(contextPointer))
  281. }
  282. public func markSeenMessages(messageIds: [UInt32]) {
  283. messageIds.withUnsafeBufferPointer { ptr in
  284. dc_markseen_msgs(contextPointer, ptr.baseAddress, Int32(ptr.count))
  285. }
  286. }
  287. private func getChatMessages(chatId: Int) -> OpaquePointer {
  288. return dc_get_chat_msgs(contextPointer, UInt32(chatId), UInt32(DC_GCM_ADDDAYMARKER), 0)
  289. }
  290. public func getMsgInfo(msgId: Int) -> String {
  291. if let cString = dc_get_msg_info(self.contextPointer, UInt32(msgId)) {
  292. let swiftString = String(cString: cString)
  293. dc_str_unref(cString)
  294. return swiftString
  295. }
  296. return "ErrGetMsgInfo"
  297. }
  298. public func getMsgHtml(msgId: Int) -> String {
  299. guard let cString = dc_get_msg_html(self.contextPointer, UInt32(msgId)) else { return "" }
  300. let swiftString = String(cString: cString)
  301. dc_str_unref(cString)
  302. return swiftString
  303. }
  304. public func deleteMessage(msgId: Int) {
  305. dc_delete_msgs(contextPointer, [UInt32(msgId)], 1)
  306. }
  307. public func deleteMessages(msgIds: [Int]) {
  308. dc_delete_msgs(contextPointer, msgIds.compactMap { UInt32($0) }, Int32(msgIds.count))
  309. }
  310. public func forwardMessage(with msgId: Int, to chat: Int) {
  311. dc_forward_msgs(contextPointer, [UInt32(msgId)], 1, UInt32(chat))
  312. }
  313. public func forwardMessages(with msgIds: [Int], to chat: Int) {
  314. dc_forward_msgs(contextPointer, msgIds.compactMap { UInt32($0) }, Int32(msgIds.count), UInt32(chat))
  315. }
  316. public func sendTextInChat(id: Int, message: String) {
  317. dc_send_text_msg(contextPointer, UInt32(id), message)
  318. }
  319. public func initiateKeyTransfer() -> String? {
  320. if let cString = dc_initiate_key_transfer(self.contextPointer) {
  321. let swiftString = String(cString: cString)
  322. dc_str_unref(cString)
  323. return swiftString
  324. }
  325. return nil
  326. }
  327. public func continueKeyTransfer(msgId: Int, setupCode: String) -> Bool {
  328. return dc_continue_key_transfer(self.contextPointer, UInt32(msgId), setupCode) != 0
  329. }
  330. public func configure() {
  331. maxConfigureProgress = 0
  332. lastWarningString = ""
  333. dc_configure(contextPointer)
  334. }
  335. public func setChatMuteDuration(chatId: Int, duration: Int) {
  336. dc_set_chat_mute_duration(self.contextPointer, UInt32(chatId), Int64(duration))
  337. }
  338. public func setChatEphemeralTimer(chatId: Int, duration: Int) {
  339. dc_set_chat_ephemeral_timer(self.contextPointer, UInt32(chatId), UInt32(duration))
  340. }
  341. public func getChatEphemeralTimer(chatId: Int) -> Int {
  342. return Int(dc_get_chat_ephemeral_timer(self.contextPointer, UInt32(chatId)))
  343. }
  344. public func getConfig(_ key: String) -> String? {
  345. guard let cString = dc_get_config(self.contextPointer, key) else { return nil }
  346. let value = String(cString: cString)
  347. dc_str_unref(cString)
  348. if value.isEmpty {
  349. return nil
  350. }
  351. return value
  352. }
  353. public func setConfig(_ key: String, _ value: String?) {
  354. if let v = value {
  355. dc_set_config(self.contextPointer, key, v)
  356. } else {
  357. dc_set_config(self.contextPointer, key, nil)
  358. }
  359. }
  360. public func getConfigBool(_ key: String) -> Bool {
  361. return strToBool(getConfig(key))
  362. }
  363. public func setConfigBool(_ key: String, _ value: Bool) {
  364. let vStr = value ? "1" : "0"
  365. setConfig(key, vStr)
  366. }
  367. public func getConfigInt(_ key: String) -> Int {
  368. if let str = getConfig(key) {
  369. return Int(str) ?? 0
  370. }
  371. return 0
  372. }
  373. public func setConfigInt(_ key: String, _ value: Int) {
  374. setConfig(key, String(value))
  375. }
  376. public func getUnreadMessages(chatId: Int) -> Int {
  377. return Int(dc_get_fresh_msg_cnt(contextPointer, UInt32(chatId)))
  378. }
  379. public func estimateDeletionCnt(fromServer: Bool, timeout: Int) -> Int {
  380. return Int(dc_estimate_deletion_cnt(contextPointer, fromServer ? 1 : 0, Int64(timeout)))
  381. }
  382. public func isConfigured() -> Bool {
  383. return dc_is_configured(contextPointer) != 0
  384. }
  385. public func getSelfAvatarImage() -> UIImage? {
  386. guard let fileName = selfavatar else { return nil }
  387. let path: URL = URL(fileURLWithPath: fileName, isDirectory: false)
  388. if path.isFileURL {
  389. do {
  390. let data = try Data(contentsOf: path)
  391. return UIImage(data: data)
  392. } catch {
  393. logger?.warning("failed to load image: \(fileName), \(error)")
  394. return nil
  395. }
  396. }
  397. return nil
  398. }
  399. public func setChatProfileImage(chatId: Int, path: String?) {
  400. dc_set_chat_profile_image(contextPointer, UInt32(chatId), path)
  401. }
  402. @discardableResult
  403. public func addDeviceMessage(label: String?, msg: DcMsg) -> Int {
  404. return Int(dc_add_device_msg(contextPointer, label, msg.cptr))
  405. }
  406. public func getProviderFromEmail(addr: String) -> DcProvider? {
  407. guard let dcProviderPointer = dc_provider_new_from_email(contextPointer, addr) else { return nil }
  408. return DcProvider(dcProviderPointer)
  409. }
  410. public func imex(what: Int32, directory: String) {
  411. dc_imex(contextPointer, what, directory, nil)
  412. }
  413. public func imexHasBackup(filePath: String) -> String? {
  414. var file: String?
  415. if let cString = dc_imex_has_backup(contextPointer, filePath) {
  416. file = String(cString: cString)
  417. dc_str_unref(cString)
  418. }
  419. return file
  420. }
  421. public func isSendingLocationsToChat(chatId: Int) -> Bool {
  422. return dc_is_sending_locations_to_chat(contextPointer, UInt32(chatId)) == 1
  423. }
  424. public func sendLocationsToChat(chatId: Int, seconds: Int) {
  425. dc_send_locations_to_chat(contextPointer, UInt32(chatId), Int32(seconds))
  426. }
  427. public func setLocation(latitude: Double, longitude: Double, accuracy: Double) {
  428. dc_set_location(contextPointer, latitude, longitude, accuracy)
  429. }
  430. public func searchMessages(chatId: Int = 0, searchText: String) -> [Int] {
  431. let start = CFAbsoluteTimeGetCurrent()
  432. guard let arrayPointer = dc_search_msgs(contextPointer, UInt32(chatId), searchText) else {
  433. return []
  434. }
  435. let messageIds = DcUtils.copyAndFreeArray(inputArray: arrayPointer)
  436. let diff = CFAbsoluteTimeGetCurrent() - start
  437. logger?.info("⏰ searchMessages: \(diff) s")
  438. return messageIds
  439. }
  440. // also, there is no much worth in adding a separate function or so
  441. // for each config option - esp. if they are just forwarded to the core
  442. // and set/get only at one line of code each.
  443. // this adds a complexity that can be avoided -
  444. // and makes grep harder as these names are typically named following different guidelines.
  445. public var displayname: String? {
  446. get { return getConfig("displayname") }
  447. set { setConfig("displayname", newValue) }
  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. }
  943. public class DcContact {
  944. private var contactPointer: OpaquePointer?
  945. public init(contactPointer: OpaquePointer?) {
  946. self.contactPointer = contactPointer
  947. }
  948. deinit {
  949. dc_contact_unref(contactPointer)
  950. }
  951. public var displayName: String {
  952. guard let cString = dc_contact_get_display_name(contactPointer) else { return "" }
  953. let swiftString = String(cString: cString)
  954. dc_str_unref(cString)
  955. return swiftString
  956. }
  957. public var nameNAddr: String {
  958. guard let cString = dc_contact_get_name_n_addr(contactPointer) else { return "" }
  959. let swiftString = String(cString: cString)
  960. dc_str_unref(cString)
  961. return swiftString
  962. }
  963. public var editedName: String {
  964. guard let cString = dc_contact_get_name(contactPointer) else { return "" }
  965. let swiftString = String(cString: cString)
  966. dc_str_unref(cString)
  967. return swiftString
  968. }
  969. public var authName: String {
  970. guard let cString = dc_contact_get_auth_name(contactPointer) else { return "" }
  971. let swiftString = String(cString: cString)
  972. dc_str_unref(cString)
  973. return swiftString
  974. }
  975. public var email: String {
  976. guard let cString = dc_contact_get_addr(contactPointer) else { return "" }
  977. let swiftString = String(cString: cString)
  978. dc_str_unref(cString)
  979. return swiftString
  980. }
  981. public var status: String {
  982. guard let cString = dc_contact_get_status(contactPointer) else { return "" }
  983. let swiftString = String(cString: cString)
  984. dc_str_unref(cString)
  985. return swiftString
  986. }
  987. public var isVerified: Bool {
  988. return dc_contact_is_verified(contactPointer) > 0
  989. }
  990. public var isBlocked: Bool {
  991. return dc_contact_is_blocked(contactPointer) == 1
  992. }
  993. public lazy var profileImage: UIImage? = { [weak self] in
  994. guard let cString = dc_contact_get_profile_image(contactPointer) else { return nil }
  995. let filename = String(cString: cString)
  996. dc_str_unref(cString)
  997. let path: URL = URL(fileURLWithPath: filename, isDirectory: false)
  998. if path.isFileURL {
  999. do {
  1000. let data = try Data(contentsOf: path)
  1001. return UIImage(data: data)
  1002. } catch {
  1003. print("failed to load image: \(filename), \(error)")
  1004. return nil
  1005. }
  1006. }
  1007. return nil
  1008. }()
  1009. public var profileImageURL: URL? {
  1010. guard let cString = dc_contact_get_profile_image(contactPointer) else { return nil }
  1011. let filename = String(cString: cString)
  1012. dc_str_unref(cString)
  1013. return URL(fileURLWithPath: filename, isDirectory: false)
  1014. }
  1015. public var color: UIColor {
  1016. return UIColor(netHex: Int(dc_contact_get_color(contactPointer)))
  1017. }
  1018. public var id: Int {
  1019. return Int(dc_contact_get_id(contactPointer))
  1020. }
  1021. }
  1022. public class DcLot {
  1023. private var dcLotPointer: OpaquePointer?
  1024. // takes ownership of specified pointer
  1025. public init(_ dcLotPointer: OpaquePointer) {
  1026. self.dcLotPointer = dcLotPointer
  1027. }
  1028. deinit {
  1029. dc_lot_unref(dcLotPointer)
  1030. }
  1031. public var text1: String? {
  1032. guard let cString = dc_lot_get_text1(dcLotPointer) else { return nil }
  1033. let swiftString = String(cString: cString)
  1034. dc_str_unref(cString)
  1035. return swiftString
  1036. }
  1037. public var text1Meaning: Int {
  1038. return Int(dc_lot_get_text1_meaning(dcLotPointer))
  1039. }
  1040. public var text2: String? {
  1041. guard let cString = dc_lot_get_text2(dcLotPointer) else { return nil }
  1042. let swiftString = String(cString: cString)
  1043. dc_str_unref(cString)
  1044. return swiftString
  1045. }
  1046. public var timestamp: Int64 {
  1047. return Int64(dc_lot_get_timestamp(dcLotPointer))
  1048. }
  1049. public var state: Int {
  1050. return Int(dc_lot_get_state(dcLotPointer))
  1051. }
  1052. public var id: Int {
  1053. return Int(dc_lot_get_id(dcLotPointer))
  1054. }
  1055. }
  1056. public class DcProvider {
  1057. private var dcProviderPointer: OpaquePointer?
  1058. // takes ownership of specified pointer
  1059. public init(_ dcProviderPointer: OpaquePointer) {
  1060. self.dcProviderPointer = dcProviderPointer
  1061. }
  1062. deinit {
  1063. dc_provider_unref(dcProviderPointer)
  1064. }
  1065. public var status: Int {
  1066. return Int(dc_provider_get_status(dcProviderPointer))
  1067. }
  1068. public var beforeLoginHint: String {
  1069. guard let cString = dc_provider_get_before_login_hint(dcProviderPointer) else { return "" }
  1070. let swiftString = String(cString: cString)
  1071. dc_str_unref(cString)
  1072. return swiftString
  1073. }
  1074. public var getOverviewPage: String {
  1075. guard let cString = dc_provider_get_overview_page(dcProviderPointer) else { return "" }
  1076. let swiftString = String(cString: cString)
  1077. dc_str_unref(cString)
  1078. return swiftString
  1079. }
  1080. }
  1081. public enum MessageViewType: CustomStringConvertible {
  1082. case audio
  1083. case file
  1084. case gif
  1085. case image
  1086. case text
  1087. case video
  1088. case voice
  1089. public var description: String {
  1090. switch self {
  1091. // Use Internationalization, as appropriate.
  1092. case .audio: return "Audio"
  1093. case .file: return "File"
  1094. case .gif: return "GIF"
  1095. case .image: return "Image"
  1096. case .text: return "Text"
  1097. case .video: return "Video"
  1098. case .voice: return "Voice"
  1099. }
  1100. }
  1101. }
  1102. func strToBool(_ value: String?) -> Bool {
  1103. if let vStr = value {
  1104. if let vInt = Int(vStr) {
  1105. return vInt == 1
  1106. }
  1107. return false
  1108. }
  1109. return false
  1110. }