def servePage(self, view, url, params): if url == "/edit": selectedLang = params.get('lang', None) if selectedLang and len(selectedLang) == 2: Config.setProperty(Config.KEY_LANGUAGE, selectedLang) # I18nManager will be triggered here because it listens to the Config fsf = params.get('friendsseefriends', None) friendsseefriends = fsf is not None and len(fsf) > 0 Config.setProperty(Config.KEY_ALLOW_FRIENDS_TO_SEE_FRIENDS, friendsseefriends) slw = params.get('showlogwindow', None) showlogwindow = slw is not None and len(slw) > 0 Config.setProperty(Config.KEY_SHOW_LOG_WINDOW, showlogwindow) # If Config has changed, may need to update profile to include/hide friends info DbClient.updateContactList(friendsseefriends) # When friends are notified next time, the profile's hash will be calculated and sent afw = params.get('allowfriendrequests', None) allowfriendrequests = afw is not None and len(afw) > 0 Config.setProperty(Config.KEY_ALLOW_FRIEND_REQUESTS, allowfriendrequests) # Save config to file in case it's changed Config.save() contents = self.buildPage({'pageTitle' : I18nManager.getText("settings.title"), 'pageBody' : "<p>Settings changed... should I go back to settings or back to home now?</p>", 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents) else: pageProps = {"friendsseefriends" : "checked" if Config.getProperty(Config.KEY_ALLOW_FRIENDS_TO_SEE_FRIENDS) else "", "allowfriendrequests" : "checked" if Config.getProperty(Config.KEY_ALLOW_FRIEND_REQUESTS) else "", "showlogwindow" : "checked" if Config.getProperty(Config.KEY_SHOW_LOG_WINDOW) else "", "language_en":"", "language_de":""} pageProps["language_" + Config.getProperty(Config.KEY_LANGUAGE)] = "selected" #print("body:", self.formtemplate.getHtml(pageProps)) contents = self.buildPage({'pageTitle' : I18nManager.getText("settings.title"), 'pageBody' : self.formtemplate.getHtml(pageProps), 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents)
def servePage(self, view, url, params): if url == "/edit": selectedLang = params.get('lang', None) if selectedLang and len(selectedLang) == 2: Config.setProperty(Config.KEY_LANGUAGE, selectedLang) # I18nManager will be triggered here because it listens to the Config fsf = params.get('friendsseefriends', None) friendsseefriends = fsf is not None and len(fsf) > 0 Config.setProperty(Config.KEY_ALLOW_FRIENDS_TO_SEE_FRIENDS, friendsseefriends) slw = params.get('showlogwindow', None) showlogwindow = slw is not None and len(slw) > 0 Config.setProperty(Config.KEY_SHOW_LOG_WINDOW, showlogwindow) # If Config has changed, may need to update profile to include/hide friends info DbI.updateContactList(friendsseefriends) # When friends are notified next time, the profile's hash will be calculated and sent afw = params.get('allowfriendrequests', None) allowfriendrequests = afw is not None and len(afw) > 0 Config.setProperty(Config.KEY_ALLOW_FRIEND_REQUESTS, allowfriendrequests) # Save config to file in case it's changed Config.save() contents = self.buildPage({ 'pageTitle': I18nManager.getText("settings.title"), 'pageBody': "<p>Settings changed... should I go back to settings or back to home now?</p>", 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents) else: pageProps = { "friendsseefriends": "checked" if Config.getProperty( Config.KEY_ALLOW_FRIENDS_TO_SEE_FRIENDS) else "", "allowfriendrequests": "checked" if Config.getProperty( Config.KEY_ALLOW_FRIEND_REQUESTS) else "", "showlogwindow": "checked" if Config.getProperty(Config.KEY_SHOW_LOG_WINDOW) else "", "language_en": "", "language_de": "" } pageProps["language_" + Config.getProperty(Config.KEY_LANGUAGE)] = "selected" #print("body:", self.formtemplate.getHtml(pageProps)) contents = self.buildPage({ 'pageTitle': I18nManager.getText("settings.title"), 'pageBody': self.formtemplate.getHtml(pageProps), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents)
def enableButtons(self, card): '''Ask the card what the button texts and enabled status should be''' backKey, nextKey = card.getButtonKeys() self.backButton.setText(I18nManager.getText("button." + backKey)) self.nextButton.setText(I18nManager.getText("button." + nextKey)) backEnabled, nextEnabled = card.getButtonsEnabled() self.backButton.setEnabled(backEnabled) self.nextButton.setEnabled(nextEnabled)
def __init__(self, *args): self.logPanel = LogWindow() GuiWindow.__init__(self, lowerItem=self.logPanel) self.clearWebCache() self.postmen = None self.toolbar = self.makeToolbar([ ("images/toolbar-home.png", self.onHomeClicked, "mainwindow.toolbar.home"), ("images/toolbar-people.png", self.onContactsClicked, "mainwindow.toolbar.contacts"), ("images/toolbar-messages.png", self.onMessagesClicked, "mainwindow.toolbar.messages"), ("images/toolbar-messages-highlight.png", self.onMessagesClicked, "mainwindow.toolbar.messages"), ("images/toolbar-calendar.png", self.onCalendarClicked, "mainwindow.toolbar.calendar"), ("images/toolbar-settings.png", self.onSettingsClicked, "mainwindow.toolbar.settings") ]) self.addToolBar(self.toolbar) self.setContextMenuPolicy(QtCore.Qt.NoContextMenu) # status bar self.statusbar = QtWidgets.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.setWindowTitle(I18nManager.getText("mainwindow.title")) self.setStatusTip("Murmeli") self.setPageServer(PageServer()) self.navigateTo("/") # we want to be notified of Config changes Config.registerSubscriber(self) self.postmen = [ postmen.IncomingPostman(self), postmen.OutgoingPostman(self) ] self.postmen[1].messageSentSignal.connect(self.logPanel.notifyLogEvent) MessageShuffler.getTannoy().updateSignal.connect( self.logPanel.notifyLogEvent) # Make sure Tor client is started if not TorClient.isStarted(): TorClient.startTor() # Create database instance if not already set if not DbI.hasDbSet(): DbI.setDb(MurmeliDb(Config.getSsDatabaseFile())) # Make sure the status of the contacts matches our keyring missingKeyNames = ContactMaker.checkAllContactsKeys() if missingKeyNames: warningTexts = [I18nManager.getText("warning.keysnotfoundfor") ] + missingKeyNames QtWidgets.QMessageBox.warning(self, "Murmeli", "\n ".join(warningTexts))
def servePage(self, view, url, params): print("Special function:", url) if url == "/selectprofilepic": # Get home directory for file dialog homedir = os.path.expanduser("~/") fname = QtGui.QFileDialog.getOpenFileName(view, I18nManager.getText("gui.dialogtitle.openimage"), homedir, I18nManager.getText("gui.fileselection.filetypes.jpg")) if fname: view.page().mainFrame().evaluateJavaScript("updateProfilePic('" + fname + "');") elif url == "/friendstorm": if not DbClient.hasFriends(): view.page().mainFrame().evaluateJavaScript("window.alert('No friends :(');") return # Launch a storm self.bs = Brainstorm(I18nManager.getText("contacts.storm.title")) self.bs.show() storm = Storm() # Build up Nodes and Edges using our contact list and if possible our friends' contact lists myTorId = DbClient.getOwnTorId() friends = {} friendsOfFriends = {} for c in DbClient.getContactList(): #print("Contact:", c['torid'], "'", c['displayName'], "'") nodeid = storm.getUnusedNodeId() torid = c['torid'] friends[torid] = nodeid storm.addNode(Node(None, nodeid, c['displayName'])) friendsOfFriends[torid] = c.get('contactlist', "") for torid in friends: if torid != myTorId: storm.addEdge(friends[torid], friends[myTorId]) for torid in friendsOfFriends: if torid != myTorId: ffList = friendsOfFriends[torid] if ffList: for ff in ffList.split(","): if ff and len(ff) > 16: ffTorid = ff[:16] ffName = ff[16:] if ffTorid != myTorId: if not friends.get(ffTorid, None): # Friend's friend is not in the list yet - add it nodeid = storm.getUnusedNodeId() friends[ffTorid] = nodeid storm.addNode(Node(None, nodeid, ffName)) # Add edge from torid to ffTorid storm.addEdge(friends[torid], friends[ffTorid]) self.bs.setStorm(storm)
def servePage(self, view, url, params): DbClient.exportAvatars(Config.getWebCacheDir()) if url == "/send": print("send message of type '%(messageType)s' to id '%(sendTo)s'" % params) elif url.startswith("/delete/"): DbClient.deleteMessageFromInbox(params.get("msgId", "")) # Make dictionary to convert ids to names contactNames = {c['torid']:c['displayName'] for c in DbClient.getContactList()} unknownSender = I18nManager.getText("messages.sender.unknown") unknownRecpt = I18nManager.getText("messages.recpt.unknown") # Get contact requests, responses and mails from inbox conreqs = [] conresps = [] mails = [] for m in DbClient.getInboxMessages(): m['msgId'] = str(m.get("_id", "")) if m['messageType'] == "contactrequest": conreqs.append(m) elif m['messageType'] == "contactrefer": senderId = m.get('fromId', None) m['senderName'] = contactNames.get(senderId, unknownSender) conreqs.append(m) elif m['messageType'] == "contactresponse": if not m.get('accepted', False): m['messageBody'] = I18nManager.getText("messages.contactrequest.refused") m['fromName'] = DbClient.getProfile(m['fromId'], True).get("displayName") elif not m.get('messageBody', False): m['messageBody'] = I18nManager.getText("messages.contactrequest.accepted") conresps.append(m) else: senderId = m.get('fromId', None) if not senderId and m.get('signatureKeyId', None): senderId = DbClient.findUserIdFromKeyId(m['signatureKeyId']) m['senderName'] = contactNames.get(senderId, unknownSender) m['sentTimeStr'] = self.makeLocalTimeString(m['timestamp']) # Split m['recipients'] by commas, and look up each id with contactNames recpts = m.get('recipients', '') if recpts: m['recipients'] = ", ".join([contactNames.get(i, unknownRecpt) for i in recpts.split(",")]) else: m['recipients'] = unknownRecpt mails.append(m) bodytext = self.messagestemplate.getHtml({"contactrequests":conreqs, "contactresponses":conresps, "mails":mails, "nummessages":len(conreqs)+len(conresps)+len(mails), "webcachedir" : Config.getWebCacheDir()}) contents = self.buildPage({'pageTitle' : I18nManager.getText("messages.title"), 'pageBody' : bodytext, 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents)
def generateFingerprintsPage(self, userid): '''Build the page for checking the fingerprints of the selected user''' # First, get the name of the user person = DbClient.getProfile(userid, False) dispName = person.get('displayName', '') fullName = person.get('name', '') if not dispName: dispName = fullName if dispName != fullName: fullName = dispName + " (" + fullName + ")" fc = self._makeFingerprintChecker(userid) # check it's ok to generate status = person.get('status', '') if not fc.valid \ or status not in ['untrusted', 'trusted']: print("Not generating fingerprints page because status is", status) return None # Get one set of words for us and three sets for them printsAlreadyChecked = (person.get('status', '') == "trusted") bodytext = self.fingerprintstemplate.getHtml( {"mywords":fc.getCodeWords(True, 0, "en"), "theirwords0":fc.getCodeWords(False, 0, "en"), "theirwords1":fc.getCodeWords(False, 1, "en"), "theirwords2":fc.getCodeWords(False, 2, "en"), "fullname":fullName, "shortname":dispName, "userid":userid, "alreadychecked":printsAlreadyChecked}) return self.buildPage({'pageTitle' : I18nManager.getText("contacts.title"), 'pageBody' : bodytext, 'pageFooter' : "<p>Footer</p>"})
def _makeHeadingLabel(self, token): '''Convenience method for making a bold label for each panel''' label = QtWidgets.QLabel(I18nManager.getText(token)) boldFont = label.font() boldFont.setWeight(QtGui.QFont.Bold) boldFont.setPointSize(boldFont.pointSize() + 1) label.setFont(boldFont) return label
def _makeHeadingLabel(self, token): '''Convenience method for making a bold label for each panel''' label = QtGui.QLabel(I18nManager.getText(token)) boldFont = label.font() boldFont.setWeight(QtGui.QFont.Bold) boldFont.setPointSize(boldFont.pointSize() + 1) label.setFont(boldFont) return label
def configUpdated(self): '''React to a change in settings by changing tooltips and log panel visibility''' for a in self.toolbarActions: a.setToolTip(I18nManager.getText(a.tooltipkey)) # Show/hide log window if Config.getProperty(Config.KEY_SHOW_LOG_WINDOW): self.logPanel.show() else: self.logPanel.hide()
def finishedServiceCheck(self): '''Called when service check has been completed by the other thread''' self.updatedServiceCheck() # make sure all icons are updated self.checksDone = True self.allOk = self.checkerThread.allGood() self.servicesCheckLabel.setText(I18nManager.getText("startupwizard.services." + \ ("allstarted" if self.allOk else "notallstarted"))) self.labels["abouttostart"].setVisible(False) # emit signal back to controller self.redrawNavButtonsSignal.emit()
def servePage(self, view, url, params): contents = self.buildPage({ 'pageTitle': I18nManager.getText("calendar.title"), 'pageBody': self.calendartemplate.getHtml(), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents)
def finishedServiceCheck(self): '''Called when service check has been completed by the other thread''' self.updatedServiceCheck() # make sure all icons are updated self.checksDone = True self.allOk = self.checkerThread.allGood() self.servicesCheckLabel.setText(I18nManager.getText("startupwizard.services." + \ ("allstarted" if self.allOk else "notallstarted"))) self.labels["abouttostart"].setVisible(False) # emit signal back to controller self.panel.emit(QtCore.SIGNAL('redrawNavButtons()'))
def servePage(self, view, url, params): print("Compose: %s, params %s" % (url, ",".join(params))) if url == "/start": self.requirePageResources(['default.css']) parentHash = params.get("reply", None) recpts = params.get("sendto", None) # Build list of contacts to whom we can send userboxes = [] for p in DbClient.getMessageableContacts(): box = Bean() box.dispName = p['displayName'] box.torid = p['torid'] userboxes.append(box) pageParams = {"contactlist":userboxes, "parenthash" : parentHash if parentHash else "", "webcachedir":Config.getWebCacheDir(), "recipientids":recpts} contents = self.buildPage({'pageTitle' : I18nManager.getText("composemessage.title"), 'pageBody' : self.composetemplate.getHtml(pageParams), 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents) # If we've got no friends, then warn, can't send to anyone if not DbClient.hasFriends(): view.page().mainFrame().evaluateJavaScript("window.alert('No friends :(');") elif url == "/send": print("Submit new message with params:", params) msgBody = params['messagebody'] # TODO: check body isn't empty, throw an exception? parentHash = params.get("parenthash", None) recpts = params['sendto'] # Make a corresponding message object and pass it on msg = message.RegularMessage(sendTo=recpts, messageBody=msgBody, replyToHash=parentHash) msg.recipients = recpts.split(",") DbClient.addMessageToOutbox(msg) # Save a copy of the sent message sentMessage = {"messageType":"normal", "fromId":DbClient.getOwnTorId(), "messageBody":msgBody, "timestamp":msg.timestamp, "messageRead":True, "messageReplied":False, "recipients":recpts, "parentHash":parentHash} DbClient.addMessageToInbox(sentMessage) # Close window after successful send contents = self.buildPage({'pageTitle' : I18nManager.getText("messages.title"), 'pageBody' : self.closingtemplate.getHtml(), 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents)
def generateAddPage(self): '''Build the form page for adding a new user, using the template''' bodytext = self.addtemplate.getHtml({"owntorid": DbI.getOwnTorid()}) return self.buildPage({ 'pageTitle': I18nManager.getText("contacts.title"), 'pageBody': bodytext, 'pageFooter': "<p>Footer</p>" })
def getPanel(self): # fifth panel, for generating keypair self.panel = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() self.labels = {} for k in [ "heading", "introemptykeyring", "introsinglekey", "introselectkey", "param.name", "param.email", "param.comment", "mighttakeawhile" ]: self.labels[k] = QtWidgets.QLabel() self._makeLabelHeading(self.labels["heading"]) layout.addWidget(self.labels["heading"]) layout.addStretch(0.3) layout.addWidget(self.labels["introemptykeyring"]) layout.addWidget(self.labels["introsinglekey"]) layout.addWidget(self.labels["introselectkey"]) # list of keypairs already in the keyring self.keypairListWidget = QtWidgets.QListWidget() layout.addWidget(self.keypairListWidget) # parameters for generation of new keypair self.keygenbox = QtWidgets.QFrame(self.panel) sublayout = QtWidgets.QFormLayout() self.keygenParamBoxes = {} for param in ['name', 'email', 'comment']: # (no password) editbox = QtWidgets.QLineEdit() self.keygenParamBoxes[param] = editbox sublayout.addRow(self.labels["param." + param], editbox) self.keygenbox.setLayout(sublayout) sublayout.setFormAlignment( QtCore.Qt.AlignHCenter) # horizontally centred layout.addWidget(self.keygenbox) # 'Generate' button self.generateButton = QtWidgets.QPushButton( I18nManager.getText("button.generate")) self.generateButton.clicked.connect(self.generateKeyClicked) layout.addWidget(self.generateButton) # Progress bar (actually more of an hourglass) self.generateProgressbar = QtWidgets.QProgressBar() self.generateProgressbar.setVisible(False) self.generateProgressbar.setMinimum(0) self.generateProgressbar.setMaximum(0) progressPanel = QtWidgets.QFrame() sublayout = QtWidgets.QHBoxLayout() sublayout.addStretch(0.4) sublayout.addWidget(self.generateProgressbar) sublayout.addStretch(0.4) progressPanel.setLayout(sublayout) layout.addWidget(progressPanel) # Label to say that it might take a minute or two layout.addWidget(self.labels["mighttakeawhile"]) layout.addStretch(1) self.panel.setLayout(layout) return self.panel
def __init__(self, *args): '''Constructor''' QtWidgets.QMainWindow.__init__(*(self, ) + args) self.setWindowTitle(I18nManager.getText("startupwizard.title")) # main pane with the stack and the button panel mainpane = QtWidgets.QWidget(self) mainlayout = QtWidgets.QVBoxLayout() mainpane.setLayout(mainlayout) self.setCentralWidget(mainpane) self.cardstack = QtWidgets.QStackedWidget(mainpane) self.cardPanels = [IntroPanel(), DependenciesPanel(), PathsPanel(), ServicesPanel(), \ KeygenPanel(), FinishedPanel()] for card in self.cardPanels: panel = card.getPanel() self.cardstack.addWidget(panel) card.redrawNavButtonsSignal.connect(self.redrawButtons) # button panel at the bottom buttonPanel = QtWidgets.QFrame(self.cardstack) buttonPanel.setFrameStyle(QtWidgets.QFrame.Box + QtWidgets.QFrame.Sunken) self.backButton = QtWidgets.QPushButton( I18nManager.getText("button.exit")) self.nextButton = QtWidgets.QPushButton( I18nManager.getText("button.next")) layout = QtWidgets.QHBoxLayout() layout.addWidget(self.backButton) layout.addStretch(1) layout.addWidget(self.nextButton) buttonPanel.setLayout(layout) self.backButton.clicked.connect(self.backButtonClicked) self.nextButton.clicked.connect(self.nextButtonClicked) mainlayout.addWidget(self.cardstack) mainlayout.addWidget(buttonPanel) self.nextButton.setFocus()
def servePage(self, view, url, params): domain, path = self.getDomainAndPath(url) # Do I need to intercept this to create a new window? if domain == "new": cw = ComposeWindow(I18nManager.getText("composemessage.title")) cw.setPageServer(self) cw.showPage("<html></html>") cw.navigateTo(path, params) return server = self.pageSets.get(domain) if not server: server = self.pageSets.get("") server.servePage(view, path, params)
def prepare(self): '''When going from the intro page to the dependencies page, this needs to be updated''' depsFound = {'pyqt':True} # PyQt must be present, otherwise we wouldn't be here! self.allFound = True try: import pymongo depsFound["pymongo"] = True except: self.allFound = False try: from gnupg import GPG depsFound["gnupg"] = True except: self.allFound = False # Update the ticks and crosses for l in self.dependencyLabels: found = depsFound.get(l.depkey, False) l.setPixmap(self.yesPixmap if found else self.noPixmap) l.setToolTip(I18nManager.getText("startupwizard.dep.found" if found else "startupwizard.dep.notfound")) # if not all dependencies are there, show the message self.dependencyCheckLabel.setText(I18nManager.getText("startupwizard.dependencies." + ("allfound" if self.allFound else "notallfound")))
def finish(self): '''Called when leaving the paths page''' datadir = str(self.dataDirectoryField.text()) Config.setProperty(Config.KEY_DATA_DIR, datadir) # Make sure all the directories exist, create them if not try: for direc in [Config.getDatabaseDir(), Config.getWebCacheDir(), \ Config.getKeyringDir(), Config.getTorDir()]: if not os.path.exists(direc): os.makedirs(direc) except: # Couldn't create one of the directories, so show error and stay on this panel QtWidgets.QMessageBox.critical( self.panel, I18nManager.getText("gui.dialogtitle.error"), I18nManager.getText( "startupwizard.paths.failedtocreatedatadir")) return False # Also store selected paths to exes # TODO: Check the exes exist? Config.setProperty(Config.KEY_TOR_EXE, str(self.torPathField.text())) Config.setProperty(Config.KEY_GPG_EXE, str(self.gpgPathField.text())) Config.save() return True
def finish(self): '''Called when leaving the paths page''' datadir = str(self.dataDirectoryField.text()) Config.setProperty(Config.KEY_DATA_DIR, datadir) # Make sure all the directories exist, create them if not try: for direc in [Config.getDatabaseDir(), Config.getWebCacheDir(), \ Config.getKeyringDir(), Config.getTorDir()]: if not os.path.exists(direc): os.makedirs(direc) except: # Couldn't create one of the directories, so show error and stay on this panel QtGui.QMessageBox.critical(self.panel, I18nManager.getText("gui.dialogtitle.error"), I18nManager.getText("startupwizard.paths.failedtocreatedatadir")) return False # Also store selected paths to exes # TODO: Check the exes exist? Config.setProperty(Config.KEY_MONGO_EXE, str(self.mongoPathField.text())) Config.setProperty(Config.KEY_TOR_EXE, str(self.torPathField.text())) Config.setProperty(Config.KEY_GPG_EXE, str(self.gpgPathField.text())) Config.save() return True
def __init__(self, *args): '''Constructor''' QtGui.QMainWindow.__init__(*(self,) + args) self.setWindowTitle(I18nManager.getText("startupwizard.title")) # main pane with the stack and the button panel mainpane = QtGui.QWidget(self) mainlayout = QtGui.QVBoxLayout() mainpane.setLayout(mainlayout) self.setCentralWidget(mainpane) self.cardstack = QtGui.QStackedWidget(mainpane) self.cardPanels = [IntroPanel(), DependenciesPanel(), PathsPanel(), ServicesPanel(), \ KeygenPanel(), FinishedPanel()] for card in self.cardPanels: panel = card.getPanel() self.cardstack.addWidget(panel) self.connect(panel, QtCore.SIGNAL("redrawNavButtons()"), self.redrawButtons) # button panel at the bottom buttonPanel = QtGui.QFrame(self.cardstack) buttonPanel.setFrameStyle(QtGui.QFrame.Box + QtGui.QFrame.Sunken) self.backButton = QtGui.QPushButton(I18nManager.getText("button.exit")) self.nextButton = QtGui.QPushButton(I18nManager.getText("button.next")) layout = QtGui.QHBoxLayout() layout.addWidget(self.backButton) layout.addStretch(1) layout.addWidget(self.nextButton) buttonPanel.setLayout(layout) self.connect(self.backButton, QtCore.SIGNAL("clicked()"), self.backButtonClicked) self.connect(self.nextButton, QtCore.SIGNAL("clicked()"), self.nextButtonClicked) mainlayout.addWidget(self.cardstack) mainlayout.addWidget(buttonPanel) self.nextButton.setFocus()
def getPanel(self): # fifth panel, for generating keypair self.panel = QtGui.QWidget() layout = QtGui.QVBoxLayout() self.labels = {} for k in ["heading", "introemptykeyring", "introsinglekey", "introselectkey", "param.name", "param.email", "param.comment", "mighttakeawhile"]: self.labels[k] = QtGui.QLabel() self._makeLabelHeading(self.labels["heading"]) layout.addWidget(self.labels["heading"]) layout.addStretch(0.3) layout.addWidget(self.labels["introemptykeyring"]) layout.addWidget(self.labels["introsinglekey"]) layout.addWidget(self.labels["introselectkey"]) # list of keypairs already in the keyring self.keypairListWidget = QtGui.QListWidget() layout.addWidget(self.keypairListWidget) # parameters for generation of new keypair self.keygenbox = QtGui.QFrame(self.panel) sublayout = QtGui.QFormLayout() self.keygenParamBoxes = {} for param in ['name', 'email', 'comment']: # (no password) editbox = QtGui.QLineEdit() self.keygenParamBoxes[param] = editbox sublayout.addRow(self.labels["param." + param], editbox) self.keygenbox.setLayout(sublayout) sublayout.setFormAlignment(QtCore.Qt.AlignHCenter) # horizontally centred layout.addWidget(self.keygenbox) # 'Generate' button self.generateButton = QtGui.QPushButton(I18nManager.getText("button.generate")) self.panel.connect(self.generateButton, QtCore.SIGNAL("clicked()"), self.generateKeyClicked) layout.addWidget(self.generateButton) # Progress bar (actually more of an hourglass) self.generateProgressbar = QtGui.QProgressBar() self.generateProgressbar.setVisible(False) self.generateProgressbar.setMinimum(0) self.generateProgressbar.setMaximum(0) progressPanel = QtGui.QFrame() sublayout = QtGui.QHBoxLayout() sublayout.addStretch(0.4) sublayout.addWidget(self.generateProgressbar) sublayout.addStretch(0.4) progressPanel.setLayout(sublayout) layout.addWidget(progressPanel) # Label to say that it might take a minute or two layout.addWidget(self.labels["mighttakeawhile"]) layout.addStretch(1) self.panel.setLayout(layout) return self.panel
def generateListPage(self, doEdit=False, userid=None, extraParams=None): self.requirePageResources(['avatar-none.jpg', 'status-self.png', 'status-requested.png', 'status-untrusted.png', 'status-trusted.png']) # List of contacts, and show details for the selected one (or self if userid=None) selectedprofile = DbClient.getProfile(userid) if selectedprofile is None: selectedprofile = DbClient.getProfile() userid = selectedprofile['torid'] ownPage = userid == DbClient.getOwnTorId() # Build list of contacts userboxes = [] for p in DbClient.getContactList(): box = Bean() box.dispName = p['displayName'] box.torid = p['torid'] box.tilestyle = "contacttile" + ("selected" if p['torid'] == userid else "") box.status = p['status'] box.isonline = Contacts.isOnline(box.torid) userboxes.append(box) # expand templates using current details lefttext = self.listtemplate.getHtml({'webcachedir' : Config.getWebCacheDir(), 'contacts' : userboxes}) pageProps = {"webcachedir" : Config.getWebCacheDir(), 'person':selectedprofile} # Add extra parameters if necessary if extraParams: pageProps.update(extraParams) # See which contacts we have in common with this person (sharedContactIds, possIdsForThem, possIdsForMe, nameMap) = ContactMaker.getSharedAndPossibleContacts(userid) sharedContacts = self._makeIdAndNameBeanList(sharedContactIds, nameMap) pageProps.update({"sharedcontacts" : sharedContacts}) possibleContacts = self._makeIdAndNameBeanList(possIdsForThem, nameMap) pageProps.update({"possiblecontactsforthem" : possibleContacts}) possibleContacts = self._makeIdAndNameBeanList(possIdsForMe, nameMap) pageProps.update({"possiblecontactsforme" : possibleContacts}) # Which template to use depends on whether we're just showing or also editing if doEdit: # Use two different details templates, one for self and one for others detailstemplate = self.editowndetailstemplate if ownPage else self.editdetailstemplate righttext = detailstemplate.getHtml(pageProps) else: detailstemplate = self.detailstemplate # just show righttext = detailstemplate.getHtml(pageProps) contents = self.buildTwoColumnPage({'pageTitle' : I18nManager.getText("contacts.title"), 'leftColumn' : lefttext, 'rightColumn' : righttext, 'pageFooter' : "<p>Footer</p>"}) return contents
def prepare(self): '''When going from the intro page to the dependencies page, this needs to be updated''' depsFound = { 'pyqt': True } # PyQt must be present, otherwise we wouldn't be here! self.allFound = True try: from gnupg import GPG depsFound["gnupg"] = True except: self.allFound = False # Update the ticks and crosses for l in self.dependencyLabels: found = depsFound.get(l.depkey, False) l.setPixmap(self.yesPixmap if found else self.noPixmap) l.setToolTip( I18nManager.getText("startupwizard.dep.found" if found else "startupwizard.dep.notfound")) # if not all dependencies are there, show the message self.dependencyCheckLabel.setText( I18nManager.getText("startupwizard.dependencies." + ( "allfound" if self.allFound else "notallfound")))
def servePage(self, view, url, params): domain, path = self.getDomainAndPath(url) # Do I need to intercept this to create a new window? if domain == "new": cw = ComposeWindow(I18nManager.getText("composemessage.title")) cw.setPageServer(self) cw.showPage("<html></html>") cw.navigateTo(path, params) # TODO: Remove the closed windows from the list self._openWindows.append(cw) return server = self.pageSets.get(domain) if not server: server = self.pageSets.get("") server.servePage(view, path, params)
def generateFingerprintsPage(self, userid): '''Build the page for checking the fingerprints of the selected user''' # First, get the name of the user person = DbI.getProfile(userid) dispName = person['displayName'] fullName = person['name'] if dispName != fullName: fullName = dispName + " (" + fullName + ")" fc = self._makeFingerprintChecker(userid) # check it's ok to generate status = person.get('status', '') if not fc.valid \ or status not in ['untrusted', 'trusted']: print("Not generating fingerprints page because status is", status) return None # Get one set of words for us and three sets for them printsAlreadyChecked = (person.get('status', '') == "trusted") bodytext = self.fingerprintstemplate.getHtml({ "mywords": fc.getCodeWords(True, 0, "en"), "theirwords0": fc.getCodeWords(False, 0, "en"), "theirwords1": fc.getCodeWords(False, 1, "en"), "theirwords2": fc.getCodeWords(False, 2, "en"), "fullname": fullName, "shortname": dispName, "userid": userid, "alreadychecked": printsAlreadyChecked }) return self.buildPage({ 'pageTitle': I18nManager.getText("contacts.title"), 'pageBody': bodytext, 'pageFooter': "<p>Footer</p>" })
def prepare(self): '''Called before showing the keypair page''' self.privateKeys = CryptoClient.getPrivateKeys() numKeys = len(self.privateKeys) self.labels["introemptykeyring"].setVisible(numKeys == 0) self.labels["introsinglekey"].setVisible(numKeys == 1) self.labels["introselectkey"].setVisible(numKeys > 1) self.generateProgressbar.setVisible(False) self.labels["mighttakeawhile"].setVisible(False) self.keypairListWidget.clear() for k in self.privateKeys: name = k['uids'] if isinstance(name, list): name = str(name[0]) self.keypairListWidget.addItem("%s - %s (%s)" % (k['keyid'], name, k['length'])) self.keypairListWidget.setVisible(numKeys > 0) self.keypairListWidget.setCurrentRow(self.keypairListWidget.count() - 1) # Hide generation option if we've got a key already self.keygenbox.setVisible(numKeys == 0) self.generateButton.setVisible(numKeys == 0) # Rewrite button text in case language has changed self.generateButton.setText(I18nManager.getText("button.generate"))
def servePage(self, view, url, params): contents = self.buildPage({'pageTitle' : I18nManager.getText("calendar.title"), 'pageBody' : self.calendartemplate.getHtml(), 'pageFooter' : "<p>Footer</p>"}) view.setHtml(contents)
def generateAddPage(self): '''Build the form page for adding a new user, using the template''' bodytext = self.addtemplate.getHtml({"owntorid" : DbClient.getOwnTorId()}) return self.buildPage({'pageTitle' : I18nManager.getText("contacts.title"), 'pageBody' : bodytext, 'pageFooter' : "<p>Footer</p>"})
def generateListPage(self, doEdit=False, userid=None, extraParams=None): self.requirePageResources([ 'avatar-none.jpg', 'status-self.png', 'status-requested.png', 'status-untrusted.png', 'status-trusted.png', 'status-pending.png' ]) # List of contacts, and show details for the selected one (or self if userid=None) selectedprofile = DbI.getProfile(userid) if not selectedprofile: selectedprofile = DbI.getProfile() userid = selectedprofile['torid'] ownPage = userid == DbI.getOwnTorid() # Build list of contacts userboxes = [] currTime = datetime.datetime.now() for p in DbI.getProfiles(): box = Bean() box.dispName = p['displayName'] box.torid = p['torid'] box.tilestyle = "contacttile" + ("selected" if p['torid'] == userid else "") box.status = p['status'] isonline = Contacts.instance().isOnline(box.torid) lastSeen = Contacts.instance().lastSeen(box.torid) lastSeenTime = str(lastSeen.timetz())[:5] if lastSeen and ( currTime - lastSeen).total_seconds() < 18000 else None if lastSeenTime: box.lastSeen = I18nManager.getText( "contacts.onlinesince" if isonline else "contacts.offlinesince") % lastSeenTime elif isonline: box.lastSeen = I18nManager.getText("contacts.online") else: box.lastSeen = None userboxes.append(box) # expand templates using current details lefttext = self.listtemplate.getHtml({ 'webcachedir': Config.getWebCacheDir(), 'contacts': userboxes }) pageProps = { "webcachedir": Config.getWebCacheDir(), 'person': selectedprofile } # Add extra parameters if necessary if extraParams: pageProps.update(extraParams) # See which contacts we have in common with this person (sharedContactIds, possIdsForThem, possIdsForMe, nameMap) = ContactMaker.getSharedAndPossibleContacts(userid) sharedContacts = self._makeIdAndNameBeanList(sharedContactIds, nameMap) pageProps.update({"sharedcontacts": sharedContacts}) possibleContacts = self._makeIdAndNameBeanList(possIdsForThem, nameMap) pageProps.update({"possiblecontactsforthem": possibleContacts}) possibleContacts = self._makeIdAndNameBeanList(possIdsForMe, nameMap) pageProps.update({"possiblecontactsforme": possibleContacts}) # Which template to use depends on whether we're just showing or also editing if doEdit: # Use two different details templates, one for self and one for others detailstemplate = self.editowndetailstemplate if ownPage else self.editdetailstemplate righttext = detailstemplate.getHtml(pageProps) else: detailstemplate = self.detailstemplate # just show righttext = detailstemplate.getHtml(pageProps) contents = self.buildTwoColumnPage({ 'pageTitle': I18nManager.getText("contacts.title"), 'leftColumn': lefttext, 'rightColumn': righttext, 'pageFooter': "<p>Footer</p>" }) return contents
layout.addWidget(self.youridLabel) layout.addStretch(1) panel5.setLayout(layout) return panel5 def prepare(self): '''Prepare the final panel''' text = (I18nManager.getText("startupwizard.finished.yourid") % TorClient.getOwnId()) self.youridLabel.setText(text) # TODO: If this is just a label, then it can't be selected and copied- should it be a disabled text field instead? def getButtonKeys(self): return ("back", "finish") def getButtonsEnabled(self): return (False, True) if __name__ == "__main__": # Get ready to launch a Qt GUI Config.load() I18nManager.setLanguage() Config.registerSubscriber(I18nManager.instance()) app = QtWidgets.QApplication([]) win = StartupWizard() win.show() app.exec_()
def prepare(self): '''Prepare the final panel''' text = (I18nManager.getText("startupwizard.finished.yourid") % TorClient.getOwnId()) self.youridLabel.setText(text)
def redrawLabels(self): '''Reset the texts for all labels if the language changes''' for labelKey in list(self.labels.keys()): textKey = "startupwizard." + self.getName() + "." + labelKey self.labels[labelKey].setText(I18nManager.getText(textKey))
def servePage(self, view, url, params): print("Compose: %s, params %s" % (url, repr(params))) if url == "/start": self.requirePageResources(['default.css', 'jquery-3.1.1.js']) DbI.exportAllAvatars(Config.getWebCacheDir()) parentHash = params.get("reply", None) recpts = params.get("sendto", None) # Build list of contacts to whom we can send userboxes = [] for p in DbI.getMessageableProfiles(): box = Bean() box.dispName = p['displayName'] box.torid = p['torid'] userboxes.append(box) pageParams = { "contactlist": userboxes, "parenthash": parentHash if parentHash else "", "webcachedir": Config.getWebCacheDir(), "recipientids": recpts } contents = self.buildPage({ 'pageTitle': I18nManager.getText("composemessage.title"), 'pageBody': self.composetemplate.getHtml(pageParams), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents) # If we've got no friends, then warn, can't send to anyone if not DbI.hasFriends(): view.page().mainFrame().evaluateJavaScript( "window.alert('No friends :(');") elif url == "/send": print("Submit new message with params:", params) msgBody = params[ 'messagebody'] # TODO: check body isn't empty, throw an exception? parentHash = params.get("parenthash", None) recpts = params['sendto'] # Make a corresponding message object and pass it on msg = message.RegularMessage(sendTo=recpts, messageBody=msgBody, replyToHash=parentHash) msg.recipients = recpts.split(",") DbI.addToOutbox(msg) # Save a copy of the sent message sentMessage = { "messageType": "normal", "fromId": DbI.getOwnTorid(), "messageBody": msgBody, "timestamp": msg.timestamp, "messageRead": True, "messageReplied": False, "recipients": recpts, "parentHash": parentHash } DbI.addToInbox(sentMessage) # Close window after successful send contents = self.buildPage({ 'pageTitle': I18nManager.getText("messages.title"), 'pageBody': self.closingtemplate.getHtml(), 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents)
layout.addWidget(self.labels["nowstart"]) self.youridLabel = QtGui.QLabel() layout.addWidget(self.youridLabel) layout.addStretch(1) panel5.setLayout(layout) return panel5 def prepare(self): '''Prepare the final panel''' text = (I18nManager.getText("startupwizard.finished.yourid") % TorClient.getOwnId()) self.youridLabel.setText(text) # TODO: If this is just a label, then it can't be selected and copied- should it be a disabled text field instead? def getButtonKeys(self): return ("back", "finish") def getButtonsEnabled(self): return (False, True) if __name__ == "__main__": # Get ready to launch a Qt GUI Config.load() I18nManager.setLanguage() Config.registerSubscriber(I18nManager.instance()) app = QtGui.QApplication([]) win = StartupWizard() win.show() app.exec_()
def servePage(self, view, url, params): print("Special function:", url) if url == "/selectprofilepic": # Get home directory for file dialog homedir = os.path.expanduser("~/") fname = QFileDialog.getOpenFileName( view, I18nManager.getText("gui.dialogtitle.openimage"), homedir, I18nManager.getText("gui.fileselection.filetypes.jpg")) if fname: view.page().mainFrame().evaluateJavaScript( "updateProfilePic('" + fname + "');") elif url == "/friendstorm": if not DbI.hasFriends(): view.page().mainFrame().evaluateJavaScript( "window.alert('No friends :(');") return # Launch a storm self.bs = Brainstorm(I18nManager.getText("contacts.storm.title")) self.bs.show() storm = Storm() # Build up Nodes and Edges using our contact list and if possible our friends' contact lists myTorId = DbI.getOwnTorid() friends = {} friendsOfFriends = {} for c in DbI.getMessageableProfiles(): # print("Contact: id:'%s' name:'%s'" % (c['torid'], c['displayName'])) nodeid = storm.getUnusedNodeId() torid = c['torid'] friends[torid] = nodeid storm.addNode(Node(None, nodeid, c['displayName'])) friendsOfFriends[torid] = c.get('contactlist', "") # Also add ourselves c = DbI.getProfile() nodeid = storm.getUnusedNodeId() friends[c['torid']] = nodeid storm.addNode(Node(None, nodeid, c['displayName'])) # Add edges for torid in friends: if torid != myTorId: storm.addEdge(friends[torid], friends[myTorId]) for torid in friendsOfFriends: if torid != myTorId: ffList = friendsOfFriends[torid] if ffList: for ff in ffList.split(","): if ff and len(ff) > 16: ffTorid = ff[:16] ffName = ff[16:] if ffTorid != myTorId: if not friends.get(ffTorid, None): # Friend's friend is not in the list yet - add it nodeid = storm.getUnusedNodeId() friends[ffTorid] = nodeid storm.addNode( Node(None, nodeid, ffName)) # Add edge from torid to ffTorid storm.addEdge(friends[torid], friends[ffTorid]) self.bs.setStorm(storm)
def servePage(self, view, url, params): self.requirePageResources( ['button-compose.png', 'default.css', 'jquery-3.1.1.js']) DbI.exportAllAvatars(Config.getWebCacheDir()) messageList = None if url == "/send": print("send message of type '%(messageType)s' to id '%(sendTo)s'" % params) if params['messageType'] == "contactresponse": torId = params['sendTo'] if params.get("accept", "0") == "1": ContactMaker.handleAccept(torId) # Make sure this new contact has an empty avatar DbI.exportAllAvatars(Config.getWebCacheDir()) outmsg = message.ContactResponseMessage( message=params['messageBody']) else: ContactMaker.handleDeny(torId) outmsg = message.ContactDenyMessage() # Construct a ContactResponse message object for sending outmsg.recipients = [params['sendTo']] DbI.addToOutbox(outmsg) elif url.startswith("/delete/"): DbI.deleteFromInbox(params.get("msgId", "")) elif url in ["/search", "/search/"]: messageList = DbI.searchInboxMessages(params.get("searchTerm")) # Make dictionary to convert ids to names contactNames = { c['torid']: c['displayName'] for c in DbI.getProfiles() } unknownSender = I18nManager.getText("messages.sender.unknown") unknownRecpt = I18nManager.getText("messages.recpt.unknown") # Get contact requests, responses and mails from inbox conreqs = [] conresps = [] mailTree = MessageTree() if messageList is None: messageList = DbI.getInboxMessages() # TODO: Paging options? for m in messageList: if not m: continue m['msgId'] = str(m.get("_id", "")) if m['messageType'] == "contactrequest": conreqs.append(m) elif m['messageType'] == "contactrefer": senderId = m.get('fromId', None) m['senderName'] = contactNames.get(senderId, unknownSender) conreqs.append(m) elif m['messageType'] == "contactresponse": if not m.get('accepted', False): m['messageBody'] = I18nManager.getText( "messages.contactrequest.refused") m['fromName'] = DbI.getProfile(m['fromId'])["displayName"] elif not m.get('messageBody', False): m['messageBody'] = I18nManager.getText( "messages.contactrequest.accepted") conresps.append(m) else: senderId = m.get('fromId', None) if not senderId and m.get('signatureKeyId', None): senderId = DbI.findUserIdFromKeyId(m['signatureKeyId']) m['senderName'] = contactNames.get(senderId, unknownSender) m['sentTimeStr'] = self.makeLocalTimeString(m['timestamp']) # Split m['recipients'] by commas, and look up each id with contactNames recpts = m.get('recipients', '') if recpts: replyAll = recpts.split(",") m['recipients'] = ", ".join( [contactNames.get(i, unknownRecpt) for i in replyAll]) replyAll.append(senderId) m['replyAll'] = ",".join(replyAll) else: m['recipients'] = unknownRecpt m['replyAll'] = "" mailTree.addMsg(m) mails = mailTree.build() bodytext = self.messagestemplate.getHtml({ "contactrequests": conreqs, "contactresponses": conresps, "mails": mails, "nummessages": len(conreqs) + len(conresps) + len(mails), "webcachedir": Config.getWebCacheDir() }) contents = self.buildPage({ 'pageTitle': I18nManager.getText("messages.title"), 'pageBody': bodytext, 'pageFooter': "<p>Footer</p>" }) view.setHtml(contents)