mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 16:13:15 +00:00
Stalwart 1.0 checks names more strictly than its capability says: a reserved name may not be the stem either (`con.txt`, `Aux.tar.gz`), and control characters are refused (macOS `Icon\r`). Names over 255 bytes of UTF-8 were never accepted. Uploaded names are now made acceptable before they are sent: control characters become "_", a reserved stem gets "_" after it (`con.txt` becomes `con_.txt`), and a long name is shortened, keeping its extension. The rename and new-folder dialogs refuse such names with their own messages. The rules apply wherever the server publishes naming rules, so 0.16.6 to 0.16.23 get `con_.txt` too. One refused file used to abort a whole upload. Uploads now go on and report the files that failed at the end, and a folder upload skips the contents of a folder it could not create instead of dropping them into the folder the upload started in. What would sit deeper than 1.0's `maxFileNodeDepth` (64) is left out before it is uploaded, and a folder copy that would go past it fails before the first create. File errors keep their JMAP type, and the Files toasts now say why an action failed: too many files or folders (`overQuota`), folders nested too deeply, a refused name, missing rights, or a file too large. New and copied files get a bare lowercase media type, which 1.0 requires.
19 lines
701 B
TypeScript
19 lines
701 B
TypeScript
import type { FileNode } from './types';
|
|
|
|
/**
|
|
* How deep a node sits in `nodes`: 0 for the root (`null`), 1 for a node at
|
|
* the top level. Stalwart 1.0 refuses a node below its maxFileNodeDepth,
|
|
* counted this way. A parent missing from the listing ends the walk, so the
|
|
* result can only come out low.
|
|
*/
|
|
export function fileNodeDepth(nodes: Pick<FileNode, 'id' | 'parentId'>[], id: string | null): number {
|
|
const parents = new Map(nodes.map(n => [n.id, n.parentId ?? null]));
|
|
const seen = new Set<string>();
|
|
let depth = 0;
|
|
for (let current = id; current !== null && !seen.has(current); current = parents.get(current) ?? null) {
|
|
seen.add(current);
|
|
depth++;
|
|
}
|
|
return depth;
|
|
}
|