add mutt compatible processing to the query api
All checks were successful
Generic zig build / build (push) Successful in 46s
All checks were successful
Generic zig build / build (push) Successful in 46s
This commit is contained in:
parent
52affcd587
commit
df741c69ae
2 changed files with 44 additions and 4 deletions
|
@ -2,7 +2,7 @@
|
||||||
.name = .zetviel,
|
.name = .zetviel,
|
||||||
// This is a [Semantic Version](https://semver.org/).
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
// In a future version of Zig it will be used for package deduplication.
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
.version = "0.0.0",
|
.version = "0.9.0",
|
||||||
|
|
||||||
// This field is optional.
|
// This field is optional.
|
||||||
// This is currently advisory only; Zig does not yet do anything
|
// This is currently advisory only; Zig does not yet do anything
|
||||||
|
|
46
src/main.zig
46
src/main.zig
|
@ -204,8 +204,7 @@ fn queryHandler(db: *root.NotmuchDb, req: *httpz.Request, res: *httpz.Response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL decode the query
|
// URL decode the query
|
||||||
const query_buf = try db.allocator.dupe(u8, encoded_query);
|
const query_buf = try req.arena.dupe(u8, encoded_query);
|
||||||
defer db.allocator.free(query_buf);
|
|
||||||
const query = std.Uri.percentDecodeInPlace(query_buf);
|
const query = std.Uri.percentDecodeInPlace(query_buf);
|
||||||
|
|
||||||
var threads = db.search(query) catch |err| {
|
var threads = db.search(query) catch |err| {
|
||||||
|
@ -215,7 +214,48 @@ fn queryHandler(db: *root.NotmuchDb, req: *httpz.Request, res: *httpz.Response)
|
||||||
};
|
};
|
||||||
defer threads.deinit();
|
defer threads.deinit();
|
||||||
|
|
||||||
try res.json(threads, .{});
|
// Check Accept header
|
||||||
|
const accept = req.header("accept") orelse "application/json";
|
||||||
|
if (std.mem.startsWith(u8, accept, "text/plain")) {
|
||||||
|
// Parse parameters
|
||||||
|
const has_format = std.mem.indexOf(u8, accept, "format=message-ids") != null;
|
||||||
|
const separator_param = std.mem.indexOf(u8, accept, "separator=");
|
||||||
|
const has_mutt_escape = std.mem.indexOf(u8, accept, "escape=mutt") != null;
|
||||||
|
|
||||||
|
if (!has_format) {
|
||||||
|
res.status = 400;
|
||||||
|
res.body = "Invalid Accept header: text/plain requires format=message-ids";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect message IDs
|
||||||
|
var msg_ids = std.ArrayList([]const u8){};
|
||||||
|
|
||||||
|
while (try threads.next()) |*thread| {
|
||||||
|
defer thread.deinit();
|
||||||
|
var msg_iter = try thread.thread.getMessages();
|
||||||
|
while (msg_iter.next()) |msg| {
|
||||||
|
const msg_id = msg.getMessageId();
|
||||||
|
if (has_mutt_escape) {
|
||||||
|
const escaped = try std.mem.replaceOwned(u8, res.arena, msg_id, "+", "\\+");
|
||||||
|
try msg_ids.append(res.arena, escaped);
|
||||||
|
} else {
|
||||||
|
try msg_ids.append(res.arena, msg_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format output
|
||||||
|
const separator: []const u8 = if (separator_param) |s| accept[s + "separator=".len .. s + "separator=".len + 1] else "\n";
|
||||||
|
const output = try std.mem.join(res.arena, separator, msg_ids.items);
|
||||||
|
res.header("Content-Type", "text/plain");
|
||||||
|
res.body = output;
|
||||||
|
} else if (std.mem.startsWith(u8, accept, "application/json") or std.mem.eql(u8, accept, "*/*")) {
|
||||||
|
try res.json(threads, .{});
|
||||||
|
} else {
|
||||||
|
res.status = 400;
|
||||||
|
res.body = "Invalid Accept header: must be application/json or text/plain; format=message-ids";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn threadHandler(db: *root.NotmuchDb, req: *httpz.Request, res: *httpz.Response) !void {
|
fn threadHandler(db: *root.NotmuchDb, req: *httpz.Request, res: *httpz.Response) !void {
|
||||||
|
|
Loading…
Add table
Reference in a new issue