-
Notifications
You must be signed in to change notification settings - Fork 233
Quote n2ntms when replying #1043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
cddca54
5532fc3
8e2bea3
d9f6390
8c61739
fe052e3
fdc8ea0
80e3473
299fcbf
3dc8bc7
614bd95
e4d40ae
280af66
c69b7dc
14455f5
e163ed1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,9 @@ | |
| import freenet.node.NodeClientCore; | ||
| import freenet.node.NodeStarter; | ||
| import freenet.node.PeerManager; | ||
| import freenet.support.Base64; | ||
| import freenet.support.HTMLNode; | ||
| import freenet.support.IllegalBase64Exception; | ||
| import freenet.support.Logger; | ||
| import freenet.support.MultiValueTable; | ||
| import freenet.support.SizeUtil; | ||
|
|
@@ -45,44 +47,50 @@ public void handleMethodGET(URI uri, HTTPRequest request, ToadletContext ctx) | |
| return; | ||
|
|
||
| if (request.isParameterSet("peernode_hashcode")) { | ||
| PageNode page = ctx.getPageMaker().getPageNode(l10n("sendMessage"), ctx); | ||
| HTMLNode contentNode = page.getContentNode(); | ||
|
|
||
| String peernode_name = null; | ||
| String input_hashcode_string = request.getParam("peernode_hashcode"); | ||
| int input_hashcode = -1; | ||
| try { | ||
| input_hashcode = Integer.parseInt(input_hashcode_string); | ||
| } catch (NumberFormatException e) { | ||
| // ignore here, handle below | ||
| } | ||
| if (input_hashcode != -1) { | ||
| DarknetPeerNode[] peerNodes = node.getDarknetConnections(); | ||
| for (DarknetPeerNode pn: peerNodes) { | ||
| int peer_hashcode = pn.hashCode(); | ||
| if (peer_hashcode == input_hashcode) { | ||
| peernode_name = pn.getName(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (peernode_name == null) { | ||
| contentNode.addChild(createPeerInfobox("infobox-error", | ||
| l10n("peerNotFoundTitle"), l10n("peerNotFoundWithHash", | ||
| "hash", input_hashcode_string))); | ||
| this.writeHTMLReply(ctx, 200, "OK", page.generate()); | ||
| return; | ||
| } | ||
| HashMap<String, String> peers = new HashMap<String, String>(); | ||
| peers.put(input_hashcode_string, peernode_name); | ||
| createN2NTMSendForm(ctx.isAdvancedModeEnabled(), contentNode, ctx, peers); | ||
| this.writeHTMLReply(ctx, 200, "OK", page.generate()); | ||
| createWriteN2NTMForm(ctx, input_hashcode_string, ""); | ||
| return; | ||
| } | ||
| MultiValueTable<String, String> headers = MultiValueTable.from("Location", "/friends/"); | ||
| ctx.sendReplyHeaders(302, "Found", headers, null, 0); | ||
| } | ||
|
|
||
| private void createWriteN2NTMForm(ToadletContext ctx, String input_hashcode_string, String initialContent) | ||
| throws ToadletContextClosedException, IOException { | ||
| PageNode page = ctx.getPageMaker().getPageNode(l10n("sendMessage"), ctx); | ||
| HTMLNode pageNode = page.outer; | ||
| HTMLNode contentNode = page.getContentNode(); | ||
|
|
||
| String peernode_name = null; | ||
| int input_hashcode = -1; | ||
| try { | ||
| input_hashcode = Integer.parseInt(input_hashcode_string); | ||
| } catch (NumberFormatException e) { | ||
| // ignore here, handle below | ||
| } | ||
| if (input_hashcode != -1) { | ||
| DarknetPeerNode[] peerNodes = node.getDarknetConnections(); | ||
| for (DarknetPeerNode pn: peerNodes) { | ||
| int peer_hashcode = pn.hashCode(); | ||
| if (peer_hashcode == input_hashcode) { | ||
| peernode_name = pn.getName(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (peernode_name == null) { | ||
| contentNode.addChild(createPeerInfobox("infobox-error", | ||
| l10n("peerNotFoundTitle"), l10n("peerNotFoundWithHash", | ||
| "hash", input_hashcode_string))); | ||
| this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); | ||
| return; | ||
| } | ||
| HashMap<String, String> peers = new HashMap<String, String>(); | ||
| peers.put(input_hashcode_string, peernode_name); | ||
| createN2NTMSendForm(pageNode, ctx.isAdvancedModeEnabled(), contentNode, ctx, peers, initialContent); | ||
| this.writeHTMLReply(ctx, 200, "OK", pageNode.generate()); | ||
| } | ||
|
|
||
| private String l10n(String key, String pattern[], String value[]) { | ||
| return NodeL10n.getBase().getString("N2NTMToadlet." + key, pattern, value); | ||
| } | ||
|
|
@@ -138,6 +146,25 @@ public void handleMethodPOST(URI uri, HTTPRequest request, ToadletContext ctx) | |
| return; | ||
| } | ||
|
|
||
| if (request.isPartSet("replyTo")) { | ||
| String message = request.getPartAsStringFailsafe("replyTo", 1024 * 1024); | ||
| message = message.trim(); | ||
| try { | ||
| message = Base64.decodeUTF8(message); | ||
| } catch (IllegalBase64Exception e) { | ||
| Logger.error(this, "could not decode replyTo text", e); | ||
| message = ""; | ||
| } | ||
| if (!message.isEmpty()) { | ||
| message = "\n> " + String.join("\n> ", message.split("\n")) + "\n\n"; | ||
| message = message.replaceAll("\n> >", "\n>>") | ||
| .substring(1); // strip the initial linebreak again | ||
| } | ||
| String input_hashcode_string = request.getPartAsStringFailsafe("peernode_hashcode", 1024); | ||
| createWriteN2NTMForm(ctx, input_hashcode_string, message); | ||
| return; | ||
| } | ||
|
|
||
| if (request.isPartSet("n2nm-upload") || request.isPartSet(LocalFileBrowserToadlet.selectFile) || request.isPartSet("send")) { | ||
| File filename = null; | ||
| String message = request.getPartAsStringFailsafe("message", 1024 * 1024); | ||
|
|
@@ -269,6 +296,11 @@ public static void addUnsentMessageTextInfo(HTMLNode node, String message) { | |
| public static void createN2NTMSendForm(boolean advancedMode, | ||
| HTMLNode contentNode, ToadletContext ctx, HashMap<String, String> peers) | ||
| throws ToadletContextClosedException, IOException { | ||
| createN2NTMSendForm(null, advancedMode, contentNode, ctx, peers, ""); | ||
| } | ||
| public static void createN2NTMSendForm(HTMLNode pageNode, boolean advancedMode, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And can I convince you to make this method private, because there’s no reason it shouldn’t be? 😁 |
||
| HTMLNode contentNode, ToadletContext ctx, HashMap<String, String> peers, String initalContent) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There’s also a typo in the |
||
| throws ToadletContextClosedException, IOException { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The exceptions aren’t thrown anywhere. |
||
| HTMLNode infobox = contentNode.addChild("div", new String[] { "class", | ||
| "id" }, new String[] { "infobox", "n2nbox" }); | ||
| infobox.addChild("div", "class", "infobox-header", l10n("sendMessage")); | ||
|
|
@@ -288,8 +320,10 @@ public static void createN2NTMSendForm(boolean advancedMode, | |
| "value" }, new String[] { "hidden", "node_" + peerNodeHash, | ||
| "1" }); | ||
| } | ||
| messageForm.addChild("textarea", new String[] { "id", "name", "rows", | ||
| "cols" }, new String[] { "n2ntmtext", "message", "8", "74" }); | ||
| messageForm.addChild("textarea", | ||
| new String[] { "id", "name", "rows", "cols" }, | ||
| new String[] { "n2ntmtext", "message", "8", "74" }, | ||
| initalContent); | ||
| if(advancedMode){ | ||
| messageForm.addChild("br"); | ||
| messageForm.addChild("#", NodeL10n.getBase().getString("N2NTMToadlet.mayAttachFile")); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ | |
| import freenet.node.PeerNode; | ||
| import freenet.support.HTMLNode; | ||
|
|
||
| public class DownloadFeedUserAlert extends AbstractUserAlert implements NodeToNodeMessageUserAlert { | ||
| public class DownloadFeedUserAlert extends AbstractUserAlert implements UserAlertFromPeer { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion, this is going into the wrong direction. You are putting more and more content into the user alerts, but it doesn’t belong there. If you get a message from someone, that message should contain everything you need. User alerts are for showing, well, alerts. You can totally generate a user alert from e.g. a message that you have received, but none of the actual message data should be included in the alert.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I can see, there is no message. The Alerts are generated directly from SFS’s in the peer notes. We currently have this double-structure where we can answer some alerts and others we cannot, so this actually are two different concerns, munged into one structure. There are even some we can accept or reject (file offers). We could disentangle that into different objects with actual data handling (instead of managing data in what’s effectively UI objects) that get dispatched by type, but that requires more refactoring and it’s not what I currently want to achieve: my current short-term goal for next release is polishing user interface warts in friend-to-friend workflows. But I see extracting dedicated interfaces as a path towards cleaning up the structure: once the different types of alerts are represented by interfaces we can more easily swap in proper data handling (and for example have dedicated peer communication commands via FCP).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That is exactly what I see as biggest part of the problem. N2NTMs are not entities in their own right, they have been violently shoe-horned into a system that was not made for them, and the thing we absolutely should not do is entrench the notion that it’s okay for the messages (or any other actual data, for that matter) to live in the user alerts.
So you are intentionally increasing technical debt for a (questionable!) short-term goal, making it harder for us to ever fix the underlying problem? That’s quite rude! 🙂 (Why do I think your goal is questionable? Because in my opinion the biggest problems N2NTMs face – besides the name 😬 – is that nobody knows they exist, and if somebody does know they exist, they don’t know what to do with them. Adding “quote on reply” to functionality that is already obscure at best will do nothing to further its adoption, but it definitely will do is make it harder for us to actually separate N2NTMs – we need to fix this name – and user alerts, as well as everything else that is currently existing only in user alerts, making all of it available with a well-defined interface in the node and via FCP, so that you can use different clients to view and manage your N2NTMs.)
As long as all the data is living in the user alerts, you will never have this separation, and forcing it on clients to use The only forward here (again, in my opinion) is to elevate N2NTMs to be an entity in their own right, with its own in-node infrastructure and FCP interface, and then the functionality you are trying to add here will only touch the N2NTM management code and not the user alerts.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the notion that no one knows that n2ntms exists is wrong. I’ve been seeing problem reports about them for years and people with darknet peers are actively using them to share bookmarks and to write messages. My first fix to the n2ntm’s was in 2018 (to lift the 1k size restriction). I think the reason we’re not seeing those reports far more often is that few people use darknet. Which is partly because our one distinguishing feature -- truly confidential messages -- has lots of UI warts. The naming is fixed in the UI already ("send confidential message"). What I’m doing therefore is to extract a minimal interface so it doesn’t matter for the touched UI code where the data lives or whether the object is a UserAlert at all. That way we can split off storage of node messages from user alerts and only combine them in the alerts UI (for continuity), so other places can more easily get only the node to node messages (I need those as separate list in the core operations interface I’ve already been planning for too long). I think we have to move to a better structure incrementally, because other approaches regularly fail either in getting stuck or in overloading reviewers. … maybe the Interface should then not be called
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It’s hard to know which one is the cause and which one is the symptom. 😀
I would absolutely prefer if you would do that first… 🙂
We absolutely should do that, but that change is a move into the wrong direction, in my opinion, because you are making the structure worse.
I don’t have strong feelings either way about the name of this interface; I believe its existence to be a mistake. 🙂
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Core Problem is: I can’t get such a refactoring done in time for the next release (possibly next weekend), and I would really like to get communication with n2n messages more usable for the next release. If you see something that can be done without risk in a very short amount of time, I can try, otherwise I would really prefer to first get the UI improvement in and work on the structure in the background when I take up #846 again (which is the first larger change I want to do after the release). That needs messages by peers separate from UserAlerts. And yes, cause and symptom are hard to distinguish.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Using a timelimit you set yourself as a reason to get your change into Fred feels like strong-arming. 😄
That kind of implies that your change is without risk, which it decidedly is not.
Adding a function in a place as hidden as the list of 800 minor warnings is not a UI improvement; it makes our UI harder to use! An actual UI improvement would be to a) fix the name of N2NTMs (every time I’m thinking the name my brain stumbles), b) add a section in the menu bar that deals only with those messages, and c) expose them via other UIs (such as FCP). I can totally understand that you want this change to go in, and I can’t stop you, but I don’t think it’s a good change; while the intention may be pretty cool, the implementation currently does not allow this change to be made without fucking things up more than before.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’m sorry that it appears like strong-arming. The timelimit is not because I particularly like the next weekend, but because it is likely the only weekend in the next months that I can mostly use freely. But since this disturbs you that much, I’ll leave this PR out of the next release. As long as there are no new vulnerabilities we have to fix before making the code public, release 1503 should be doable without needing a dedicated weekend for it, so we should be good then, hopefully with this PR cleaned up sufficiently for inclusion.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You completely misunderstood the points of my last message. It’s not about the timelimit, it’s about that you are using the limit you yourself set as a reason to speed up integration of this PR. And it’s not about the form of this PR, it’s about what you are trying to do in the PR.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understood that. And with "form" of this PR I meant adding to UserAlerts instead of refactoring first. |
||
| private final WeakReference<PeerNode> peerRef; | ||
| private final FreenetURI uri; | ||
| private final int fileNumber; | ||
|
|
@@ -47,6 +47,11 @@ public String getText() { | |
| return sb.toString(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getMessageText() { | ||
| return description == null ? "" : description; | ||
| } | ||
|
|
||
| @Override | ||
| public String getShortText() { | ||
| return getTitle(); | ||
|
|
@@ -71,6 +76,14 @@ public HTMLNode getHTMLText() { | |
| return alertNode; | ||
| } | ||
|
|
||
| @Override | ||
| public PeerNode getSourceNode() { | ||
| if (peerRef == null) { | ||
| return null; | ||
| } | ||
| return peerRef.get(); | ||
| } | ||
|
|
||
| @Override | ||
| public String dismissButtonText() { | ||
| return l10n("delete"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof, this block is hard to understand. 🙂
This is straight from the hip, so it might need a reality check, but this captures what (I think!) you’re trying to do quite nicely.