Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ dependencies {
testImplementation "org.mockito:mockito-core:1.9.5"
testImplementation "org.hamcrest:hamcrest:3.0"
testImplementation "org.objenesis:objenesis:1.0"
testImplementation "org.jsoup:jsoup:1.21.2"
}

task tar(type: Tar) {
Expand Down
100 changes: 67 additions & 33 deletions src/freenet/clients/http/N2NTMToadlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Comment on lines +159 to +161
Copy link
Contributor

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. 🙂

Suggested change
message = "\n> " + String.join("\n> ", message.split("\n")) + "\n\n";
message = message.replaceAll("\n> >", "\n>>")
.substring(1); // strip the initial linebreak again
message = Arrays.stream(message.split("\n"))
.map(line -> "> " + line)
.map(line -> line.replaceFirst("^> >", ">>"))
.collect(joining("\n")) + "\n\n";

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.

}
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);
Expand Down Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pageNode is never used.

Copy link
Contributor

Choose a reason for hiding this comment

The 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s also a typo in the initalContent.

throws ToadletContextClosedException, IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The 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"));
Expand All @@ -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"));
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ N2NTMToadlet.uploadFailed=Das Hochladen der Datei ist fehlgeschlagen.
N2NTMUserAlert.delete=Löschen
N2NTMUserAlert.header=Von: ${from} (${composed})
N2NTMUserAlert.headerShort=Nachricht von ${from}
N2NTMUserAlert.reply=Antworten
UserAlertManager.reply=Antworten
N2NTMUserAlert.title=Knoten-zu-Knoten-Text-Nachricht ${number} von ${peername} (${peer})
Node.acceptSeedConnectionsShort=Ein Seednode sein?
Node.acceptSeedConnections=Wenn ja, wird Ihr Knoten Verbindungen von neuen Knoten, die sich im unsicheren Modus (OpenNet) befinden, akzeptieren und diesen helfen, sich aus eigener Kraft ins Netzwerk zu integrieren. Dies erlaubt es jedem Knoten mit Ihrer Knoten-Referenz sich zu verbinden, aber für Zwecke der Bekanntgabe: Er kann nur Anfragen an Knoten senden, die er durch die Bekanntgabe bekommt (möglicherweise einschließlich dieses Knotens, wenn wir nicht viele Fremde haben).
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.el.properties
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ N2NTMToadlet.sentTitle=Απεστάλη
N2NTMToadlet.uploadFailed=Αποτυχία ανεβάσματος αρχείου.
N2NTMUserAlert.delete=Διαγραφή
N2NTMUserAlert.headerShort=Μήνυμα εστάλη από ${from}
N2NTMUserAlert.reply=Απάντηση
UserAlertManager.reply=Απάντηση
NodeClientCore.minDiskFreeLongTerm=Minimum free disk space
NodeClientCore.minDiskFreeShortTerm=Minimum free disk space during decode
NodeIPDetector.maybeSymmetricTitle=Προβλήματα σύνδεσης
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ N2NTMToadlet.uploadFailed=Failed to upload file.
N2NTMUserAlert.delete=Delete
N2NTMUserAlert.header=From: ${from} (${composed})
N2NTMUserAlert.headerShort=Message from ${from}
N2NTMUserAlert.reply=Reply
UserAlertManager.reply=Reply
N2NTMUserAlert.title=Node to Node Text Message ${number} from ${peername} (${peer})
Node.acceptSeedConnectionsShort=Be a seednode?
Node.acceptSeedConnections=If true, the node will accept connections from new insecure-mode nodes and help to bootstrap them onto the network. This allows any node with your noderef to connect, but only for purposes of announcement: it can only do requests to nodes that it gets through the announcement (possibly including this node if we don't have many Strangers).
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ N2NTMToadlet.uploadFailed=Fallo al subir fichero.
N2NTMUserAlert.delete=Borrar
N2NTMUserAlert.header=De: ${from} (${composed})
N2NTMUserAlert.headerShort=Mensaje de ${from}
N2NTMUserAlert.reply=Responder
UserAlertManager.reply=Responder
N2NTMUserAlert.title=Mensaje de texto entre nodos ${number} de ${peername} (${peer})
Node.acceptSeedConnectionsShort=¿Actuar de nodo semilla?
Node.acceptSeedConnections=Si se activa, su nodo aceptará conexiones de nodos con el nuevo modo-inseguro activado, y ayudará a integrarlos en la red. Esto permite que cualquier nodo que tenga su noderef (referencia del nodo de usted) se conecte, pero únicamente con el propósito de anunciarse en la red: sólo puede hacer peticiones a nodos a los que llegue a través de anunciar (posiblemente incluyendo este mismo nodo si no tenemos muchos desconocidos).
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.fa.properties
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ N2NTMToadlet.tooLongTitle=بیش از حد طولانی
N2NTMToadlet.uploadFailed=آپلود فایل ناموفق بود.
N2NTMUserAlert.delete=حذف
N2NTMUserAlert.headerShort=پیام از ${from}
N2NTMUserAlert.reply=پاسخ
UserAlertManager.reply=پاسخ
Node.bwlimitMustBePositive=محدودیت پهنای باند آپلود باید مثبت باشد.
Node.clientCacheType=نوع حافظه نهان کلاینت؟
Node.clientCacheSize=اندازه حافظه نهان کلاینت (bytes, MB, GB, TB, غیره)
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.fi.properties
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ N2NTMToadlet.tooLongTitle=Liian pitkä
N2NTMToadlet.uploadFailed=Tiedoston lähettäminen epäonnistui.
N2NTMUserAlert.delete=Poista
N2NTMUserAlert.headerShort=Viesti lähettäjältä ${from}
N2NTMUserAlert.reply=Vastaa
UserAlertManager.reply=Vastaa
Node.acceptSeedConnectionsShort=Ole lähdesolmu
Node.assumeNATed=Oleta että porttia ei ole uudelleenohjattu.
Node.bindToLong=IP-osoite, johon kiinnittyä
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.fr.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ N2NTMToadlet.uploadFailed=Échec de téléversement du fichier.
N2NTMUserAlert.delete=Supprimer
N2NTMUserAlert.header=De : ${from} (${composed})
N2NTMUserAlert.headerShort=Message de ${from}
N2NTMUserAlert.reply=Répondre
UserAlertManager.reply=Répondre
N2NTMUserAlert.title=Message texte de nœud à nœud ${number} de ${peername} (${peer})
Node.acceptSeedConnectionsShort=Être un nœud de propagation ?
Node.acceptSeedConnections=Si cette option est vraie, le nœud acceptera les connexions de nouveaux nœuds en mode non sécurisé et les aidera à démarrer sur le réseau. Cela permet à n’importe quel nœud possédant votre réfnœud de se connecter, mais seulement dans le but de s’annoncer : ce dernier ne pourra faire de requêtes qu’aux nœuds qu’il obtiendra grâce à l’annonce (incluant possiblement ce nœud si nous n’avons pas beaucoup d’inconnus).
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.it.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ N2NTMToadlet.uploadFailed=Upload del file fallito.
N2NTMUserAlert.delete=Elimina
N2NTMUserAlert.header=Da: ${from} (${composed})
N2NTMUserAlert.headerShort=Messaggio da ${from}
N2NTMUserAlert.reply=Rispondi
UserAlertManager.reply=Rispondi
N2NTMUserAlert.title=Messaggio di testo da nodo a nodo (N2NTM) ${number} da: ${peername} (${peer})
Node.acceptSeedConnectionsShort=Abilita seednode?
Node.acceptSeedConnections=Selezionando "vero" il nodo accetterà connessioni da nodi che intendono usare la modalità insicura (opennet) e li aiuterà a connettersi alla rete Freenet. Ciò rende possibile la connessione a qualsiasi nodo in possesso della referenza ma limitata dall'annuncio: le richieste di connessione sono indirizzate solo ai nodi aggiunti tramite annuncio. Il nodo locale potrebbe essere incluso a meno che non abbia già molti peer opennet (visibili alla pagina "Sconosciuti").
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.ja.properties
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ N2NTMToadlet.returnToFriends=フレンドリストに戻る
N2NTMToadlet.tooLongTitle=長すぎる
N2NTMUserAlert.delete=削除
N2NTMUserAlert.headerShort=${from} からのメッセージ
N2NTMUserAlert.reply=返信
UserAlertManager.reply=返信
N2NTMUserAlert.title=${number} から ${peername} (${peer})へのノード間メッセージ
Node.alwaysAllowLocalAddresses=常にローカルアドレス経由での接続を許容しますか?
Node.alwaysAllowLocalAddressesLong=Trueに設定すると、Freenetはローカル(localhost, LAn)アドレス経由のノードとパブリックIPと同様に接続しようとします。これがセットされていなくても、特定のダークネットピア(オープンネットでない)には有効にできます。 もしあなたが同じLANのノードと接続したく、ニセのレファレンスであなたのノードがUDPパケットをLANのマシンに送信する危険を無視する場合セットしてください。
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.nb-no.properties
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ N2NTMToadlet.uploadFailed=Klarte ikke å laste opp fil.
N2NTMUserAlert.delete=Slett
N2NTMUserAlert.header=Fra: ${from} (${composed})
N2NTMUserAlert.headerShort=Melding fra ${from}
N2NTMUserAlert.reply=Svar
UserAlertManager.reply=Svar
N2NTMUserAlert.title=Node til Node tekstmelding ${number} fra ${peername} (${peer})
Node.acceptSeedConnectionsShort=Bli en seednode?
Node.alwaysAllowLocalAddresses=Alltid tillat tilkobling til noder via lokale adresser?
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.nl.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ N2NTMToadlet.uploadFailed=Het uploaden van het bestand is mislukt.
N2NTMUserAlert.delete=Verwijderen
N2NTMUserAlert.header=Van: ${from} (${composed})
N2NTMUserAlert.headerShort=Bericht van ${from}
N2NTMUserAlert.reply=Beantwoord
UserAlertManager.reply=Beantwoord
N2NTMUserAlert.title=Node naar Node tekstbericht ${number} van ${peername} (${peer})
Node.acceptSeedConnectionsShort=Seednode functionaliteit inschakelen?
Node.acceptSeedConnections=Indien inschakeld zal deze Freenet node verbindingen accepteren van nieuwe Vreemden en hen helpen de weg te vinden op het Freenet-netwerk. Dit zorgt ervoor dat iedere node verbinding met deze Freenet-node kan maken, maar alleen gedurende het verkenningsproces. Deze node verwerkt alleen verzoeken van nodes die reageren op een aankondigingsbericht.
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.pt-br.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ N2NTMToadlet.uploadFailed=Falha ao inserir arquivo.
N2NTMUserAlert.delete=Apagar
N2NTMUserAlert.header=De: ${from} (${composed})
N2NTMUserAlert.headerShort=Mensagem de ${from}
N2NTMUserAlert.reply=Responder
UserAlertManager.reply=Responder
N2NTMUserAlert.title=Mensagem de Texto de No a Nó ${number} de ${peername} (${peer})
Node.acceptSeedConnectionsShort=Ser um nó propagador?
Node.acceptSeedConnections=<mrk mid="0" mtype="seg">Se verdadeiro, o nó aceitará conexões de novos nós de modo inseguro e ajudará a inicializá-los na rede. </mrk><mrk mid="1" mtype="seg">Isso permite que qualquer nó com o seu noderef se conecte, mas apenas para fins de anúncio: ele só pode fazer solicitações aos nós que ele recebe através do anúncio (possivelmente incluindo este nó se não tivermos muitos Estranhos).</mrk>
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.pt_PT.properties
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ N2NTMToadlet.sendMessageShort=Enviar mensagem
N2NTMToadlet.sentTitle=Enviar
N2NTMUserAlert.delete=Eliminar
N2NTMUserAlert.headerShort=Mensagem de ${from}
N2NTMUserAlert.reply=Responder
UserAlertManager.reply=Responder
Node.bandwidthLimitMustBePositiveOrMinusOne=O limite de largura de banda de transferência deve ser positivo ou -1.
Node.bindToLong=Endereço de IP a associar
Node.clientCacheType=Tipo de cache de cliente?
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ N2NTMToadlet.uploadFailed=Сбой при выгрузке файла.
N2NTMUserAlert.delete=Удалить
N2NTMUserAlert.header=От: ${from} (${composed})
N2NTMUserAlert.headerShort=Сообщение от ${from}
N2NTMUserAlert.reply=Ответить
UserAlertManager.reply=Ответить
N2NTMUserAlert.title=Текстовое сообщение ${number} от ${peername} (${peer})
Node.acceptSeedConnectionsShort=Быть узлом-источником?
Node.acceptSeedConnections=Узел-источник принимает запросы от новых узлов Опеннета и помогает им подключиться к сети. Любой узел, который знает о вашем узле, может к вам подключиться для пересылки анонсов: такой узел сможет отсылать запросы только тем узлам, информацию о которых он получил в ответ на свой анонс (возможно, запросы будут адресованы и вам, если к вашему узлу подключено недостаточно незнакомцев).
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.sv.properties
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ N2NTMToadlet.sentTitle=Skickat
N2NTMToadlet.tooLongTitle=För långt
N2NTMUserAlert.delete=Radera
N2NTMUserAlert.headerShort=Meddelande från ${from}
N2NTMUserAlert.reply=Svara
UserAlertManager.reply=Svara
N2NTMUserAlert.title=Nod till Nod Text meddelande nummer ${number} från ${peername} (${peer})
Node.bindTo=IP adress att knyta till
Node.bindToLong=IP adress att knyta till
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.zh-cn.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,7 @@ N2NTMToadlet.uploadFailed=上传文件失败。
N2NTMUserAlert.delete=删除
N2NTMUserAlert.header=来自: ${from} (${composed})
N2NTMUserAlert.headerShort=来自 ${from} 的信息
N2NTMUserAlert.reply=回复
UserAlertManager.reply=回复
N2NTMUserAlert.title=${number} 条来自 ${peername} (${peer}) 的点对点文本信息
Node.acceptSeedConnectionsShort=作为种子节点?
Node.acceptSeedConnections=如果设置为“是”,节点将会接受新的非安全模式节点的连接并帮助它们引导到网络。这会允许任何拥有您节点信息的节点连接,但是仅用于宣告目的: 这些新节点仅能向通过宣告获得的其他节点 (如果没有足够的陌生节点,那么可能包括本节点) 请求数据。
Expand Down
2 changes: 1 addition & 1 deletion src/freenet/l10n/freenet.l10n.zh-tw.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,7 @@ N2NTMToadlet.uploadFailed=上傳檔案失敗。
N2NTMUserAlert.delete=刪除
N2NTMUserAlert.header=來自: ${from} (${composed})
N2NTMUserAlert.headerShort=來自 ${from} 的訊息
N2NTMUserAlert.reply=回覆
UserAlertManager.reply=回覆
N2NTMUserAlert.title=從${peername}(${peer})來的點對點文字訊息${number}
Node.acceptSeedConnectionsShort=作為種子節點?
Node.acceptSeedConnections=若為是, 節點會接受以不安全模式運作的新節點的連線, 並且幫助它們自載於網路上. 設為是會讓任何擁有你的參照的節點都能和你連線, 但只限於通報的用途: 該節點只能夠向經由通報取得的友點發出請求(也可能包含本節點, 如果我們沒有很多"陌生人"連線的話).
Expand Down
15 changes: 14 additions & 1 deletion src/freenet/node/useralerts/DownloadFeedUserAlert.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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).

Copy link
Contributor

Choose a reason for hiding this comment

The 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).

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.

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.

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.)

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).

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 instanceof everywhere in their code just to know if this random user alert does maybe contain a message is quite the nasty code smell.

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.

Copy link
Contributor Author

@ArneBab ArneBab Jun 24, 2025

Choose a reason for hiding this comment

The 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 UserAlertFromNode but something like MessageFromNode or FriendNote (though message is already taken for FCP message -- do you have a better suggestion?).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

It’s hard to know which one is the cause and which one is the symptom. 😀

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 would absolutely prefer if you would do that first… 🙂

I think we have to move to a better structure incrementally, because other approaches regularly fail either in getting stuck or in overloading reviewers.

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.

… maybe the Interface should then not be called UserAlertFromNode but something like MessageFromNode or FriendNote (though message is already taken for FCP message -- do you have a better suggestion?).

I don’t have strong feelings either way about the name of this interface; I believe its existence to be a mistake. 🙂

Copy link
Contributor Author

@ArneBab ArneBab Jun 24, 2025

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

@Bombe Bombe Jun 26, 2025

Choose a reason for hiding this comment

The 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.

Using a timelimit you set yourself as a reason to get your change into Fred feels like strong-arming. 😄

If you see something that can be done without risk in a very short amount of time

That kind of implies that your change is without risk, which it decidedly is not.

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).

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;
Expand Down Expand Up @@ -47,6 +47,11 @@ public String getText() {
return sb.toString();
}

@Override
public String getMessageText() {
return description == null ? "" : description;
}

@Override
public String getShortText() {
return getTitle();
Expand All @@ -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");
Expand Down
Loading