"Fossies" - the Fresh Open Source Software Archive

Member "deltachat-desktop-1.3.4/src/main/deltachat/controller.ts" (18 May 2020, 9457 Bytes) of package /linux/misc/deltachat-desktop-1.3.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "controller.ts": 1.3.3_vs_1.3.4.

    1 import DeltaChat, { C, DeltaChat as DeltaChatNode } from 'deltachat-node'
    2 import { app as rawApp } from 'electron'
    3 import { EventEmitter } from 'events'
    4 import { getLogger } from '../../shared/logger'
    5 import { LocalSettings, JsonContact } from '../../shared/shared-types'
    6 import { integerToHexColor } from '../../shared/util'
    7 import { maybeMarkSeen } from '../markseenFix'
    8 import * as mainWindow from '../windows/main'
    9 import DCAutocrypt from './autocrypt'
   10 import DCBackup from './backup'
   11 import DCChat from './chat'
   12 import DCChatList from './chatlist'
   13 import DCContacts from './contacts'
   14 import DCContext from './context'
   15 import DCLocations from './locations'
   16 import DCLoginController from './login'
   17 import DCMessageList from './messagelist'
   18 import DCSettings from './settings'
   19 import DCStickers from './stickers'
   20 import { ExtendedAppMainProcess } from '../types'
   21 import { string } from 'prop-types'
   22 import Extras from './extras'
   23 const app = rawApp as ExtendedAppMainProcess
   24 
   25 const eventStrings = require('deltachat-node/events')
   26 const log = getLogger('main/deltachat')
   27 const logCoreEvent = getLogger('core/event')
   28 
   29 /**
   30  * DeltaChatController
   31  *
   32  * - proxy for a deltachat instance
   33  * - sends events to renderer
   34  * - handles events from renderer
   35  */
   36 export default class DeltaChatController extends EventEmitter {
   37   /**
   38    * Created and owned by ipc on the backend
   39    */
   40   _dc: DeltaChat = undefined
   41   accountDir: string
   42   configuring = false
   43   updating = false
   44   ready = false
   45   credentials = { addr: '' }
   46   _selectedChatId: number | null = null
   47   _showArchivedChats = false
   48   _pages = 0
   49   _query = ''
   50   _sendStateToRenderer: () => void
   51   constructor(public cwd: string, saved: LocalSettings) {
   52     super()
   53     this._resetState()
   54     if (!saved)
   55       throw new Error(
   56         'Saved settings are a required argument to DeltaChatController'
   57       )
   58   }
   59 
   60   readonly autocrypt = new DCAutocrypt(this)
   61   readonly backup = new DCBackup(this)
   62   readonly chatList = new DCChatList(this)
   63   readonly contacts = new DCContacts(this)
   64   readonly chat = new DCChat(this)
   65   readonly locations = new DCLocations(this)
   66   readonly loginController = new DCLoginController(this)
   67   readonly messageList = new DCMessageList(this)
   68   readonly settings = new DCSettings(this)
   69   readonly stickers = new DCStickers(this)
   70   readonly context = new DCContext(this)
   71   readonly extras = new Extras(this)
   72 
   73   /**
   74    * @param {string} methodName
   75    */
   76   __resolveNestedMethod(self: DeltaChatController, methodName: string) {
   77     const parts = methodName.split('.')
   78     if (parts.length > 2) {
   79       const message =
   80         'Resolving of nested method name failed: Too many parts, only two allowed: ' +
   81         methodName
   82       log.error(message)
   83       throw new Error(message)
   84     }
   85     const scope = (self as any)[parts[0]]
   86     if (typeof scope === 'undefined') {
   87       const message = 'Resolving of nested method name failed: ' + methodName
   88       log.error(message)
   89       throw new Error(message)
   90     }
   91     const method = scope[parts[1]]
   92     if (typeof method !== 'function') {
   93       const message = '(nested) Method is not of type function: ' + methodName
   94       log.error(message)
   95       throw new Error(message)
   96     }
   97     return method.bind(scope)
   98   }
   99 
  100   /**
  101    *
  102    * @param {*} evt
  103    * @param {string} methodName
  104    * @param {*} args
  105    */
  106   async callMethod(_evt: any, methodName: string, args: any[] = []) {
  107     const method =
  108       methodName.indexOf('.') !== -1
  109         ? this.__resolveNestedMethod(this, methodName)
  110         : (methodName => {
  111             const method = (this as any)[methodName]
  112             if (typeof method !== 'function') {
  113               const message = 'Method is not of type function: ' + methodName
  114               log.error(message)
  115               throw new Error(message)
  116             }
  117             return method.bind(this)
  118           })(methodName)
  119 
  120     let returnValue
  121     try {
  122       returnValue = await method(...args)
  123     } catch (err) {
  124       log.error(
  125         `Error calling ${methodName}(${args.join(', ')}):\n ${err.stack}`
  126       )
  127     }
  128     return returnValue
  129   }
  130 
  131   sendToRenderer(eventType: string, payload?: any) {
  132     log.debug('sendToRenderer: ' + eventType, payload)
  133     mainWindow.send('ALL', eventType, payload)
  134     if (!eventType) {
  135       log.error(
  136         'Tried to send an undefined event to the renderer.\n' +
  137           'This is not allowed and will normaly produce a crash of electron'
  138       )
  139       return
  140     }
  141     mainWindow.send(eventType, payload)
  142   }
  143 
  144   translate(
  145     ...args: Parameters<import('../../shared/localize').getMessageFunction>
  146   ) {
  147     return (app as any).translate(...args)
  148   }
  149 
  150   // checkPassword(password: string) {
  151   //   return password === this.settings.getConfig('mail_pw')
  152   // }
  153 
  154   registerEventHandler(dc: DeltaChat) {
  155     // in debug mode log all core events
  156     dc.on('ALL', (_event: any, data1: any, data2: any) => {
  157       const event: string = !isNaN(_event)
  158         ? eventStrings[_event]
  159         : String(_event)
  160 
  161       if (data1 === 0) data1 = ''
  162 
  163       if (event === 'DC_EVENT_WARNING') {
  164         logCoreEvent.warn(event, data1, data2)
  165       } else if (event === 'DC_EVENT_INFO') {
  166         logCoreEvent.info(event, data1, data2)
  167       } else if (event.startsWith('DC_EVENT_ERROR')) {
  168         logCoreEvent.error(event, data1, data2)
  169       } else if (app.rc['log-debug']) {
  170         // in debug mode log all core events
  171         logCoreEvent.debug(event, data1, data2)
  172       }
  173 
  174       this.sendToRenderer(event, [data1, data2])
  175     })
  176 
  177     dc.on('DD_EVENT_CHATLIST_UPDATED', this.onChatListChanged.bind(this))
  178 
  179     // TODO: move event handling to frontend store
  180     dc.on('DC_EVENT_MSGS_CHANGED', (chatId: number, msgId: number) => {
  181       this.onChatListChanged()
  182       this.onChatListItemChanged(chatId)
  183       this.chatList.onChatModified(chatId)
  184     })
  185 
  186     dc.on('DC_EVENT_INCOMING_MSG', (chatId: number, msgId: number) => {
  187       maybeMarkSeen(chatId, msgId)
  188       this.onChatListChanged()
  189       this.onChatListItemChanged(chatId)
  190       this.chatList.onChatModified(chatId)
  191     })
  192 
  193     dc.on('DC_EVENT_CHAT_MODIFIED', (chatId: number, msgId: number) => {
  194       this.onChatListChanged()
  195       this.onChatListItemChanged(chatId)
  196       this.chatList.onChatModified(chatId)
  197     })
  198 
  199     dc.on('DC_EVENT_MSG_FAILED', (chatId: number, msgId: number) => {
  200       this.onChatListItemChanged(chatId)
  201     })
  202 
  203     dc.on('DC_EVENT_MSG_DELIVERED', (chatId: number, msgId: number) => {
  204       this.onChatListItemChanged(chatId)
  205     })
  206 
  207     dc.on('DC_EVENT_MSG_READ', (chatId: number, msgId: number) => {
  208       this.onChatListItemChanged(chatId)
  209     })
  210 
  211     dc.on('DC_EVENT_CONFIGURE_PROGRESS', (progress: string) => {
  212       if (Number(progress) === 0) {
  213         // login failed
  214         this.onLoginFailure()
  215         this.sendToRenderer('DC_EVENT_CONFIGURE_FAILED')
  216       }
  217     })
  218 
  219     dc.on('DC_EVENT_ERROR_NETWORK', (_first: any, error: any) => {
  220       if (this.configuring) {
  221         this.onLoginFailure()
  222       }
  223     })
  224   }
  225 
  226   onLoginFailure() {
  227     if (this.updating) {
  228       // error when updating login credentials when being logged in
  229       this.sendToRenderer('DC_EVENT_LOGIN_FAILED')
  230       this.configuring = false
  231       this.updating = false
  232     } else {
  233       this.loginController.logout()
  234     }
  235   }
  236 
  237   onChatListChanged() {
  238     this.sendToRenderer('DD_EVENT_CHATLIST_CHANGED', {})
  239   }
  240 
  241   onChatListItemChanged(chatId: number) {
  242     this.sendToRenderer('DD_EVENT_CHATLIST_ITEM_CHANGED', { chatId })
  243   }
  244 
  245   updateBlockedContacts() {
  246     const blockedContacts = this._blockedContacts()
  247     this.sendToRenderer('DD_EVENT_BLOCKED_CONTACTS_UPDATED', {
  248       blockedContacts,
  249     })
  250   }
  251 
  252   /**
  253    * Returns the state in json format
  254    */
  255   getState() {
  256     return {
  257       configuring: this.configuring,
  258       credentials: this.credentials,
  259       ready: this.ready,
  260     }
  261   }
  262 
  263   checkQrCode(qrCode: string) {
  264     return this._dc.checkQrCode(qrCode)
  265   }
  266 
  267   joinSecurejoin(qrCode: string) {
  268     return new Promise(resolve => {
  269       this._dc.joinSecurejoin(qrCode, resolve)
  270     })
  271   }
  272 
  273   stopOngoingProcess() {
  274     this._dc.stopOngoingProcess()
  275   }
  276 
  277   // ToDo: Deprecated, use contacts.getContact
  278   _getContact(id: number) {
  279     const contact = this._dc.getContact(id).toJson()
  280     return { ...contact, color: integerToHexColor(contact.color) }
  281   }
  282 
  283   // ToDo: move to contacts.
  284   _blockedContacts(): JsonContact[] {
  285     if (!this._dc) return []
  286     return this._dc.getBlockedContacts().map(this._getContact.bind(this))
  287   }
  288 
  289   // ToDo: move to contacts.
  290   getContacts2(listFlags: number, queryStr: string) {
  291     const distinctIds = Array.from(
  292       new Set(this._dc.getContacts(listFlags, queryStr))
  293     )
  294     const contacts = distinctIds.map(this._getContact.bind(this))
  295     return contacts
  296   }
  297 
  298   setProfilePicture(newImage: string) {
  299     this._dc.setConfig('selfavatar', newImage)
  300   }
  301 
  302   getProfilePicture() {
  303     return this._dc.getContact(C.DC_CONTACT_ID_SELF).getProfileImage()
  304   }
  305 
  306   getInfo() {
  307     if (this.ready === true) {
  308       return this._dc.getInfo()
  309     } else {
  310       return DeltaChatNode.getSystemInfo()
  311     }
  312   }
  313 
  314   getProviderInfo(email: string) {
  315     return DeltaChatNode.getProviderFromEmail(email)
  316   }
  317 
  318   /**
  319    * Internal
  320    * Reset state related to login
  321    */
  322   _resetState() {
  323     this.ready = false
  324     this.configuring = false
  325     this.credentials = { addr: '' }
  326     this._selectedChatId = null
  327     this._showArchivedChats = false
  328     this._pages = 0
  329     this._query = ''
  330   }
  331 }