def dealWithUnencryptedMessage(message): '''Decide what to do with the given unencrypted message''' if message.messageType == Message.TYPE_CONTACT_REQUEST: print("Received a contact request from", message.senderId) # Check config to see whether we accept these or not if Config.getProperty(Config.KEY_ALLOW_FRIEND_REQUESTS) \ and MessageShuffler._isProfileStatusOk(message.senderId, [None, 'requested', 'untrusted', 'trusted']): # Call DbClient to store new message in inbox rowToStore = {"messageType":"contactrequest", "fromId":message.senderId, "fromName":message.senderName, "messageBody":message.message, "publicKey":message.publicKey, "timestamp":message.timestamp, "messageRead":False, "messageReplied":False} DbClient.addMessageToInbox(rowToStore) elif message.messageType == Message.TYPE_CONTACT_RESPONSE: print("It's an unencrypted contact response, so it must be a refusal") sender = DbClient.getProfile(message.senderId, False) if MessageShuffler._isProfileStatusOk(message.senderId, ['requested']): senderName = sender.get("displayName") if sender else "" ContactMaker.handleReceiveDeny(message.senderId) # Call DbClient to store new message in inbox rowToStore = {"messageType":"contactresponse", "fromId":message.senderId, "fromName":senderName, "messageBody":"", "accepted":False, "messageRead":False, "messageReplied":False, "timestamp":message.timestamp, "recipients":MessageShuffler.getOwnTorId()} DbClient.addMessageToInbox(rowToStore) else: print("Hä? It's unencrypted but the message type is", message.messageType)
def dealWithUnencryptedMessage(message): '''Decide what to do with the given unencrypted message''' if message.messageType == Message.TYPE_CONTACT_REQUEST: print("Received a contact request from", message.senderId) # Check config to see whether we accept these or not if Config.getProperty(Config.KEY_ALLOW_FRIEND_REQUESTS) \ and MessageShuffler._isProfileStatusOk(message.senderId, [None, 'requested', 'untrusted', 'trusted']): # Store new message in inbox rowToStore = { "messageType": "contactrequest", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_CONTACT_RESPONSE: print( "It's an unencrypted contact response, so it must be a refusal" ) sender = DbI.getProfile(message.senderId) if MessageShuffler._isProfileStatusOk(message.senderId, ['requested']): senderName = sender.get("displayName") if sender else "" ContactMaker.handleReceiveDeny(message.senderId) # Store new message in inbox rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": senderName, "messageBody": "", "accepted": False, "messageRead": False, "messageReplied": False, "timestamp": message.timestamp, "recipients": DbI.getOwnTorid() } DbI.addToInbox(rowToStore) else: print("Hä? It's unencrypted but the message type is", message.messageType)
def testSharedContacts(self): # Delete whole profiles table DbClient._getProfileTable().remove({}) self.assertEqual(DbClient._getProfileTable().count(), 0, "Profiles table should be empty") # Add own profile myTorId = "ABC123DEF456GH78" myprofile = {"name" : "Constantin Taylor", "keyid" : "someKeyId", "displayName" : "Me", "status" : "self", "ownprofile" : True} DbClient.updateContact(myTorId, myprofile) # Add friend who doesn't list any contacts person1TorId = "DEF123GHI456JK78" person1profile = {"name" : "Jeremy Flintstone", "keyid" : "someKeyId", "displayName" : "Uncle Jez", "status" : "trusted"} DbClient.updateContact(person1TorId, person1profile) (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person1TorId) self.assertFalse(shared, "person1 shouldn't have any shared contacts") self.assertFalse(possIdsForThem, "person1 shouldn't have any possible contacts") self.assertFalse(possIdsForMe, "I shouldn't have any possible contacts") # Add second friend who lists first one as contact person2TorId = "GHI123JKL456MN78" person2profile = {"name" : "Karen Millhouse", "keyid" : "someKeyId", "displayName" : "Mum", "status" : "trusted", "contactlist":"DEF123GHI456JK78Jeremy,ABC123DEF456GH78Constantin,"} DbClient.updateContact(person2TorId, person2profile) (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person1TorId) self.assertEqual(len(shared), 1, "person1 should have exactly one shared contact now") self.assertTrue(person2TorId in shared, "person1 should have p2 as shared contact now") self.assertFalse(possIdsForThem, "person1 shouldn't have any possible contacts") self.assertFalse(possIdsForMe, "I shouldn't have any possible contacts from p1") (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person2TorId) self.assertEqual(len(shared), 1, "person2 should have exactly one shared contact now") self.assertTrue(person1TorId in shared, "person2 should have p1 as shared contact now") self.assertFalse(possIdsForThem, "person2 shouldn't have any possible contacts") self.assertFalse(possIdsForMe, "I shouldn't have any possible contacts from p2") # Person 2 gets a new friend DbClient.updateContact(person2TorId, {"contactlist":"DEF123GHI456JK78Jeremy,ABC123DEF456GH78Constantin,MNO123PQR456ST78Scarlet Pimpernel"}) (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person1TorId) self.assertEqual(len(shared), 1, "person1 should still have one shared contact") self.assertTrue(person2TorId in shared, "person1 should have p2 as shared contact") self.assertFalse(possIdsForThem, "person1 shouldn't have any possible contacts") (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person2TorId) self.assertEqual(len(shared), 1, "person2 should still have one shared contact") self.assertTrue(person1TorId in shared, "person2 should have p1 as shared contact") self.assertFalse(possIdsForThem, "person2 shouldn't have any possible contacts") # We now make friends with MNO person3TorId = "MNO123PQR456ST78" person3profile = {"name" : "Scarlet Pimpernel", "keyid" : "someKeyId", "displayName" : "Stranger", "status" : "trusted"} DbClient.updateContact(person3TorId, person3profile) (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person1TorId) self.assertEqual(len(shared), 1, "person1 should still have one shared contact") self.assertTrue(person2TorId in shared, "person1 should have p2 as shared contact") self.assertEqual(len(possIdsForThem), 1, "person1 should have one possible contact now") self.assertTrue(person3TorId in possIdsForThem, "person1 should have p3 as possible contact") (shared, possIdsForThem, possIdsForMe, _) = ContactMaker.getSharedAndPossibleContacts(person2TorId) self.assertEqual(len(shared), 2, "person2 should now have 2 shared contacts") self.assertTrue(person1TorId in shared, "person2 should have p1 as shared contact") self.assertTrue(person3TorId in shared, "person2 should have p3 as shared contact") self.assertFalse(possIdsForThem, "person2 shouldn't have any possible contacts")
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 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 dealWithAsymmetricMessage(message): '''Decide what to do with the given asymmetric message''' if message.senderId == DbI.getOwnTorid(): print("*** Shouldn't receive a message from myself!") return # Sort message according to type if message.messageType == Message.TYPE_CONTACT_RESPONSE: print("Received a contact accept from", message.senderId, "name", message.senderName) if MessageShuffler._isProfileStatusOk( message.senderId, ['pending', 'requested', 'untrusted']): print(message.senderName, "'s public key is", message.senderKey) ContactMaker.handleReceiveAccept(message.senderId, message.senderName, message.senderKey) # Store new message in inbox rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.introMessage, "accepted": True, "messageRead": False, "messageReplied": False, "timestamp": message.timestamp, "recipients": DbI.getOwnTorid() } DbI.addToInbox(rowToStore) elif MessageShuffler._isProfileStatusOk(message.senderId, [None, 'blocked']): print( "Received a contact response but I didn't send them a request!" ) print("Encrypted contents are:", message.encryptedContents) rowToStore = { "messageType": "contactresponse", "fromId": message.senderId, "fromName": message.senderName, "messageBody": message.introMessage, "accepted": True, "timestamp": message.timestamp, "encryptedMsg": message.encryptedContents } DbI.addMessageToPendingContacts(rowToStore) elif message.messageType == Message.TYPE_STATUS_NOTIFY: if message.online: print("One of our contacts has just come online- ", message.senderId, "and hash is", message.profileHash) prof = DbI.getProfile(message.senderId) if prof: storedHash = prof.get("profileHash", "empty") if message.profileHash != storedHash: reply = InfoRequestMessage( infoType=InfoRequestMessage.INFO_PROFILE) reply.recipients = [message.senderId] DbI.addToOutbox(reply) if message.ping: print("Now sending back a pong, too") reply = StatusNotifyMessage(online=True, ping=False, profileHash=None) reply.recipients = [message.senderId] DbI.addToOutbox(reply) else: print("It's already a pong so I won't reply") Contacts.instance().comeOnline(message.senderId) else: print("One of our contacts is going offline -", message.senderId) Contacts.instance().goneOffline(message.senderId) elif message.messageType == Message.TYPE_INFO_REQUEST: print("I've received an info request message for type", message.infoType) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): reply = InfoResponseMessage(message.messageType) reply.recipients = [message.senderId] DbI.addToOutbox(reply) elif message.messageType == Message.TYPE_INFO_RESPONSE: if message.profile and MessageShuffler._isProfileStatusOk( message.senderId, ['trusted', 'untrusted']): if message.profileHash: message.profile['profileHash'] = message.profileHash DbI.updateProfile(message.senderId, message.profile, Config.getWebCacheDir()) elif message.messageType == Message.TYPE_FRIEND_REFERRAL: print("I've received a friend referral message from:", message.senderId, "for:", message.friendName) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): # Store new referral message in inbox rowToStore = { "messageType": "contactrefer", "fromId": message.senderId, "friendId": message.friendId, "friendName": message.friendName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_FRIENDREFER_REQUEST: print("I've received a friend referral request from:", message.senderId, "who wants me to refer:", message.friendId) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): # Store message in the inbox rowToStore = { "messageType": "referrequest", "fromId": message.senderId, "friendId": message.friendId, "friendName": message.friendName, "messageBody": message.message, "publicKey": message.publicKey, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False } DbI.addToInbox(rowToStore) elif message.messageType == Message.TYPE_ASYM_MESSAGE: print( "It's a general kind of message, this should go in the Inbox, right?" ) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted', 'untrusted']): rowToStore = { "messageType": "normal", "fromId": message.senderId, "messageBody": message.messageBody, "timestamp": message.timestamp, "messageRead": False, "messageReplied": False, "recipients": message.sendTo, "parentHash": message.replyToHash } DbI.addToInbox(rowToStore) Contacts.instance().comeOnline(message.senderId) else: # It's another asymmetric message type print("Hä? What kind of asymmetric message type is that? ", message.messageType)
def dealWithAsymmetricMessage(message): '''Decide what to do with the given asymmetric message''' if message.senderId == MessageShuffler.getOwnTorId(): print("*** Shouldn't receive a message from myself!") return # Sort message according to type if message.messageType == Message.TYPE_CONTACT_RESPONSE: print("Received a contact accept from", message.senderId, "name", message.senderName) if MessageShuffler._isProfileStatusOk(message.senderId, ['pending', 'requested', 'untrusted']): print(message.senderName, "'s public key is", message.senderKey) ContactMaker.handleReceiveAccept(message.senderId, message.senderName, message.senderKey) # Call DbClient to store new message in inbox rowToStore = {"messageType":"contactresponse", "fromId":message.senderId, "fromName":message.senderName, "messageBody":message.introMessage, "accepted":True, "messageRead":False, "messageReplied":False, "timestamp":message.timestamp, "recipients":MessageShuffler.getOwnTorId()} DbClient.addMessageToInbox(rowToStore) elif MessageShuffler._isProfileStatusOk(message.senderId, [None, 'blocked']): print("Received a contact response but I didn't send them a request!") print("Encrypted contents are:", message.encryptedContents) rowToStore = {"messageType":"contactresponse", "fromId":message.senderId, "fromName":message.senderName, "messageBody":message.introMessage, "accepted":True, "timestamp":message.timestamp, "encryptedMsg":message.encryptedContents} DbClient.addMessageToPendingContacts(rowToStore) elif message.messageType == Message.TYPE_STATUS_NOTIFY: if message.online: print("One of our contacts has just come online- ", message.senderId, "and hash is", message.profileHash) prof = DbClient.getProfile(userid=message.senderId, extend=False) if prof: storedHash = prof.get("profileHash", "empty") if message.profileHash != storedHash: reply = InfoRequestMessage(infoType=InfoRequestMessage.INFO_PROFILE) reply.recipients = [message.senderId] DbClient.addMessageToOutbox(reply) if message.ping: print("Now sending back a pong, too") reply = StatusNotifyMessage(online=True, ping=False, profileHash=None) reply.recipients = [message.senderId] DbClient.addMessageToOutbox(reply) else: print("It's already a pong so I won't reply") Contacts.comeOnline(message.senderId) else: print("One of our contacts is going offline -", message.senderId) Contacts.goneOffline(message.senderId) elif message.messageType == Message.TYPE_INFO_REQUEST: print("I've received an info request message for type", message.infoType) if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted']): reply = InfoResponseMessage(message.messageType) reply.recipients = [message.senderId] DbClient.addMessageToOutbox(reply) elif message.messageType == Message.TYPE_INFO_RESPONSE: if message.profile and MessageShuffler._isProfileStatusOk(message.senderId, ['trusted', 'untrusted']): if message.profileHash: message.profile['profileHash'] = message.profileHash DbClient.updateContact(message.senderId, message.profile) elif message.messageType == Message.TYPE_ASYM_MESSAGE: print("It's a general kind of message, this should go in the Inbox, right?") if MessageShuffler._isProfileStatusOk(message.senderId, ['trusted', 'untrusted']): Contacts.comeOnline(message.senderId) else: # It's another asymmetric message type print("Hä? What kind of asymmetric message type is that? ", message.messageType)
def servePage(self, view, url, params): self.requirePageResources(['button-addperson.png', 'button-drawgraph.png', 'avatar-none.jpg']) DbClient.exportAvatars(Config.getWebCacheDir()) if url == "/add" or url == "/add/": contents = self.generateAddPage() view.setHtml(contents) return elif url == "/submitaddrequest": print("Submit add request!:", url) if len(params) > 0: # request to add a new friend recipientid = params.get('murmeliid', '') dispname = params.get('displayname', '') intromessage = params.get('intromessage', '') if len(recipientid) == 16: # TODO: How to react if: person already added (untrusted/trusted); request already sent (requested) # update the database accordingly ContactMaker.handleInitiate(recipientid, dispname) print("I should send an add request to '%s' now." % recipientid) outmsg = message.ContactRequestMessage(introMessage=intromessage) outmsg.recipients = [recipientid] DbClient.addMessageToOutbox(outmsg) else: print("Hmm, show an error message here?") # in any case, go back to contact list url = "/" + recipientid # ensure that picture is generated for new id DbClient.exportAvatars(Config.getWebCacheDir()) contents = None userid = None pageParams = {} # Split url into components /userid/command command = [i for i in url.split("/") if i != ""] if len(command) > 0 and len(command[0]) == 16 and re.match("([a-zA-Z0-9]+)$", command[0]): userid = command[0] # check for command edit or submit-edit if len(command) == 2: if command[1] == "edit": contents = self.generateListPage(doEdit=True, userid=userid) # show edit fields elif command[1] == "submitedit": DbClient.updateContact(userid, params) # don't generate contents, go back to details elif command[1] == "delete": ContactMaker.handleDeleteContact(userid) userid = None elif command[1] == "checkfingerprint": contents = self.generateFingerprintsPage(userid) elif command[1] == "checkedfingerprint": givenAnswer = int(params.get('answer', -1)) fc = self._makeFingerprintChecker(userid) expectedAnswer = fc.getCorrectAnswer() if expectedAnswer == givenAnswer: ContactMaker.keyFingerprintChecked(userid) # Show page again contents = self.generateFingerprintsPage(userid) else: # Add a message to show when the list page is re-generated pageParams['fingerprint_check_failed'] = True # If we haven't got any contents yet, then do a show details if not contents: # Show details for selected userid (or for self if userid is None) contents = self.generateListPage(doEdit=False, userid=userid, extraParams=pageParams) view.setHtml(contents)
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)
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
def servePage(self, view, url, params): self.requirePageResources([ 'button-addperson.png', 'button-drawgraph.png', 'avatar-none.jpg' ]) DbI.exportAllAvatars(Config.getWebCacheDir()) if url == "/add" or url == "/add/": contents = self.generateAddPage() view.setHtml(contents) return elif url == "/submitaddrequest": print("Submit add request!:", url) if len(params) > 0: # request to add a new friend recipientid = params.get('murmeliid', '') dispname = params.get('displayname', '') intromessage = params.get('intromessage', '') if len(recipientid) == 16: # TODO: How to react if: person already added (untrusted/trusted); request already sent (requested) # update the database accordingly ContactMaker.handleInitiate(recipientid, dispname) print("I should send an add request to '%s' now." % recipientid) outmsg = message.ContactRequestMessage( introMessage=intromessage) outmsg.recipients = [recipientid] DbI.addToOutbox(outmsg) else: print("Hmm, show an error message here?") # in any case, go back to contact list url = "/" + recipientid # ensure that picture is generated for new id DbI.exportAllAvatars(Config.getWebCacheDir()) contents = None userid = None pageParams = {} # Split url into components /userid/command command = [i for i in url.split("/") if i != ""] if len(command) > 0 and len(command[0]) == 16 and re.match( "([a-zA-Z0-9]+)$", command[0]): userid = command[0] # check for command edit or submit-edit if len(command) == 2: if command[1] == "edit": contents = self.generateListPage( doEdit=True, userid=userid) # show edit fields elif command[1] == "submitedit": DbI.updateProfile(userid, params, Config.getWebCacheDir()) # TODO: If we've updated our own details, can we trigger a broadcast? # don't generate contents, go back to details elif command[1] == "delete": ContactMaker.handleDeleteContact(userid) userid = None elif command[1] == "checkfingerprint": contents = self.generateFingerprintsPage(userid) elif command[1] == "checkedfingerprint": givenAnswer = int(params.get('answer', -1)) fc = self._makeFingerprintChecker(userid) expectedAnswer = fc.getCorrectAnswer() if expectedAnswer == givenAnswer: ContactMaker.keyFingerprintChecked(userid) # Show page again contents = self.generateFingerprintsPage(userid) else: # Add a message to show when the list page is re-generated pageParams['fingerprint_check_failed'] = True elif len(command) == 3 and command[1] == "refer" and len( command[2]) == 16: intro = str(params.get('introMessage', "")) ContactMaker.sendReferralMessages(command[0], command[2], intro) pageParams['message_sent'] = True # go back to details page elif len(command) == 3 and command[1] == "requestrefer" and len( command[2]) == 16: intro = str(params.get('introMessage', "")) ContactMaker.sendReferRequestMessage(command[0], command[2], intro) pageParams['message_sent'] = True # go back to details page # If we haven't got any contents yet, then do a show details if not contents: # Show details for selected userid (or for self if userid is None) contents = self.generateListPage(doEdit=False, userid=userid, extraParams=pageParams) view.setHtml(contents)