From 1cbc4a846c2ef4c3c1c9d4b9fa7c3b22f09f50c4 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Wed, 5 Jan 2022 11:29:14 -0800 Subject: [PATCH] add initial download for linux --- build.zig | 41 ++++++++++++++++++------- src/clipboard.zig | 62 ++++++++++++++++++++++++++++++++++++++ src/download-linux.zig | 68 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 src/download-linux.zig diff --git a/build.zig b/build.zig index ddef92c..426b2ef 100644 --- a/build.zig +++ b/build.zig @@ -17,12 +17,42 @@ pub fn build(b: *std.build.Builder) void { // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. const mode = b.standardReleaseOptions(); - const exe = switch (target.getOs().tag) { + const uploadexe = switch (target.getOs().tag) { .linux => b.addExecutable("clipboard-upload", "src/main-linux.zig"), .windows => b.addExecutable("clipboard-upload", "src/main-windows.zig"), else => std.os.exit(1), }; + configureExe(uploadexe, b, target, mode, zfetch_repo); + + const run_cmd = uploadexe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app (uplaods clipboard contents)"); + run_step.dependOn(&run_cmd.step); + + const downloadexe = switch (target.getOs().tag) { + .linux => b.addExecutable("clipboard-download", "src/download-linux.zig"), + .windows => b.addExecutable("clipboard-download", "src/download-windows.zig"), + else => std.os.exit(1), + }; + + configureExe(downloadexe, b, target, mode, zfetch_repo); + + const run_download_cmd = downloadexe.run(); + run_download_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_download_cmd.addArgs(args); + } + + const run_download_step = b.step("run-down", "Run the app (downloads clipboard contents)"); + run_download_step.dependOn(&run_download_cmd.step); +} + +fn configureExe(exe: *std.build.LibExeObjStep, b: *std.build.Builder, target: std.zig.CrossTarget, mode: std.builtin.Mode, zfetch_repo: anytype) void { exe.setTarget(target); exe.setBuildMode(mode); if (target.getOs().tag == .linux) { @@ -77,15 +107,6 @@ pub fn build(b: *std.build.Builder) void { .path = .{ .path = "libs/zfetch/libs/iguanaTLS/src/main.zig" }, }); exe.install(); - - const run_cmd = exe.run(); - run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| { - run_cmd.addArgs(args); - } - - const run_step = b.step("run", "Run the app"); - run_step.dependOn(&run_cmd.step); } fn getDependency(comptime lib_prefix: []const u8, comptime name: []const u8, comptime root: []const u8) !std.build.Pkg { diff --git a/src/clipboard.zig b/src/clipboard.zig index 1e6b2d4..5291aca 100644 --- a/src/clipboard.zig +++ b/src/clipboard.zig @@ -30,6 +30,24 @@ pub fn deinit(self: *Self) void { self.allocator.free(self.key); } +pub fn download(self: *Self) ?[]const u8 { + const encrypted = get(self.allocator) catch |e| { + std.log.err("Could not download remote clipboard contents: {}", .{e}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return null; + }; + defer self.allocator.free(encrypted); + return crypt.decryptWithKey(self.allocator, self.key.*, encrypted) catch |e| { + std.log.err("Could not decrypt remote clipboard contents: {}", .{e}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return null; + }; +} + pub fn clipboardChanged(self: *Self, contents: []const u8) !void { var arena_allocator = std.heap.ArenaAllocator.init(self.allocator); defer arena_allocator.deinit(); @@ -72,6 +90,50 @@ fn getKey(allocator: std.mem.Allocator) !*[crypt.key_size]u8 { return tmp_key; } +fn get(allocator: std.mem.Allocator) ![]const u8 { + // TODO: Windows + // var cert_reader = std.io.fixedBufferStream( + // @embedFile("/etc/ssl/certs/ca-certificates.crt"), + // ).reader(); + // const trust = try tls.x509.CertificateChain.from_pem(allocator, cert_reader); + try zfetch.init(); + defer zfetch.deinit(); + + var headers = zfetch.Headers.init(allocator); + defer headers.deinit(); + + // try headers.appendValue("Accept", "application/json"); + // try headers.appendValue("Content-Type", "text/plain"); + + var req = try zfetch.Request.init(allocator, clipboard_url, null); + defer req.deinit(); + + try req.do(.GET, headers, null); + + // Printf debugging + // const stdout = std.io.getStdOut().writer(); + // try stdout.print("status: {d} {s}\n", .{ req.status.code, req.status.reason }); + // try stdout.print("headers:\n", .{}); + // for (req.headers.list.items) |header| { + // try stdout.print(" {s}: {s}\n", .{ header.name, header.value }); + // } + // try stdout.print("body:\n", .{}); + // + const reader = req.reader(); + + var data = std.ArrayList(u8).init(allocator); + defer data.deinit(); + const data_writer = data.writer(); + var buf: [1024]u8 = undefined; + while (true) { + const read = try reader.read(&buf); + if (read == 0) break; + + try data_writer.writeAll(buf[0..read]); + } + return data.toOwnedSlice(); +} + fn post(allocator: std.mem.Allocator, data: []const u8) !void { // TODO: Windows // var cert_reader = std.io.fixedBufferStream( diff --git a/src/download-linux.zig b/src/download-linux.zig new file mode 100644 index 0000000..d969544 --- /dev/null +++ b/src/download-linux.zig @@ -0,0 +1,68 @@ +const std = @import("std"); +const Clipboard = @import("clipboard.zig"); + +pub fn main() !u8 { + var watch = false; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + var args = std.process.args(); + defer args.deinit(); + while (args.next(allocator)) |arg_or_err| { + const arg = try arg_or_err; + defer allocator.free(arg); + if (std.mem.eql(u8, arg, "-w")) { + watch = true; + break; + } + } + var clip = try Clipboard.init(allocator); + defer clip.deinit(); + if (watch) { + while (clip.download()) |text| { + std.log.debug("Got remote clipboard: {s}", .{text}); + addToClipboardNoError(allocator, text); + allocator.free(text); + } + } else { + if (clip.download()) |text| { + std.log.debug("Got remote clipboard: {s}", .{text}); + addToClipboardNoError(allocator, text); + allocator.free(text); + } + } + + return 0; +} + +fn addToClipboardNoError(allocator: std.mem.Allocator, data: []const u8) void { + addToClipboard(allocator, data) catch |e| { + std.log.err("Could not add data to clipboard: {}", .{e}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + }; +} + +fn addToClipboard(allocator: std.mem.Allocator, data: []const u8) !void { + // We're going to cheat here and just run xclip + const xclip_cmd = try std.fmt.allocPrint(allocator, "echo '{s}' | xclip -selection c", .{data}); + defer allocator.free(xclip_cmd); + + const result = try std.ChildProcess.exec(.{ + .allocator = allocator, + .argv = &[_][]const u8{ + "/usr/bin/env", + "sh", + "-c", + xclip_cmd, + }, + }); + try std.io.getStdErr().writer().writeAll(result.stderr); + switch (result.term) { + .Exited => |code| if (code != 0) return error.NonZeroExit, + .Signal => return error.FailedWithSignal, + .Stopped => return error.WasStopped, + .Unknown => return error.Failed, + } +}