This commit is contained in:
Kitteh 2021-06-02 12:03:55 +01:00
parent 85c6f583e5
commit 86e7fb6a57
6 changed files with 183 additions and 10 deletions

57
src/client.zig Normal file
View file

@ -0,0 +1,57 @@
const std = @import("std");
const read = @import("./qtshit/read.zig");
const write = @import("./qtshit/write.zig");
const qvar = @import("./qtshit/qvariant.zig");
pub const Client = struct {
allocator: *std.mem.Allocator,
stream: *std.net.Stream,
pub fn handshake(s: *Client) !void {
const magic = 0x42b33f00;
try write.add_int(s.stream.writer(), magic);
try write.add_int(s.stream.writer(), 2);
try write.add_int(s.stream.writer(), 1 << 31);
var resp = try read.get_int(s.stream.reader());
if ((resp & 0xff) != 1) {
@panic("No support 4 legacy protocol.");
}
if (((resp >> 24) & 1) != 0) {
@panic("No support 4 ssl protocol.");
}
if (((resp >> 24) & 2) != 0) {
@panic("No support 4 compression.");
}
std.debug.print("handshake Success!\n", .{});
}
pub fn quassel_init_packet(s: *Client) !void {
var map = std.StringHashMap(qvar.QVariant).init(s.allocator);
try map.put("UseSSL", .{ .byte = 0 });
try map.put("UseCompression", .{ .byte = 0 });
try map.put("ProtocolVersion", .{ .int = 10 });
try map.put("MsgType", .{ .string = "ClientInit" });
try map.put("ClientVersion", .{ .string = "0.1 (quasselclient)" });
try map.put("ClientDate", .{ .string = "0" });
try write.add_qvariantmap(s.stream.writer(), map);
}
pub fn quassel_login(s: *Client) !void {
var map = std.StringHashMap(qvar.QVariant).init(s.allocator);
try map.put("MsgType", .{ .string = "ClientLogin" });
try map.put("User", .{ .string = "z" });
try map.put("Password", .{ .string = "password" });
try write.add_qvariantmap(s.stream.writer(), map);
}
};
pub fn initClient(allocator: *std.mem.Allocator, stream: *std.net.Stream) Client {
return Client{
.allocator = allocator,
.stream = stream,
};
}

View file

@ -3,7 +3,15 @@ const std = @import("std");
const read = @import("./qtshit/read.zig"); const read = @import("./qtshit/read.zig");
const write = @import("./qtshit/write.zig"); const write = @import("./qtshit/write.zig");
const initClient = @import("./client.zig").initClient;
pub fn main() !void { pub fn main() !void {
const stdout = std.io.getStdOut().writer(); const allocator = std.heap.page_allocator;
try stdout.print("Hello, {s}!\n", .{"world"}); var sock = try std.net.tcpConnectToHost(allocator, "127.0.0.1", 64242);
var client = initClient(allocator, &sock);
try client.handshake();
try client.quassel_init_packet();
try client.quassel_login();
} }

View file

@ -1,11 +1,11 @@
const std = @import("std"); const std = @import("std");
pub const QVariant = union { pub const QVariant = union(enum) {
int: u32, int: u32,
short: u16, short: u16,
byte: u8, byte: u8,
bytearray: std.ArrayList(u8), bytearray: std.ArrayList(u8),
string: []u8, string: []const u8,
stringlist: std.ArrayList([]const u8), stringlist: std.ArrayList([]const u8),
empty: bool, empty: bool,
}; };
@ -15,8 +15,60 @@ pub const QVariantTypes = enum(u32) {
// IDK why there is 2??? // IDK why there is 2???
int_1 = 2, int_1 = 2,
int_2 = 3, int_2 = 3,
qmap = 8,
string = 10, string = 10,
stringlist = 11, stringlist = 11,
bytearray = 12, bytearray = 12,
short = 133, short = 133,
}; };
pub fn qvariant_type_id(variant: QVariant) !u32 {
switch (variant) {
.byte => {
return @enumToInt(QVariantTypes.byte);
},
.int_1, .int_2 => {
return @enumToInt(QVariantTypes.int_1);
},
.qmap => {
return @enumToInt(QVariantTypes.qmap);
},
.string => {
return @enumToInt(QVariantTypes.string);
},
.stringlist => {
return @enumToInt(QVariantTypes.stringlist);
},
.bytearray => {
return @enumToInt(QVariantTypes.bytearray);
},
.short => {
return @enumToInt(QVariantTypes.short);
},
else => {
return 0;
},
}
}
pub fn qvariant_size(variant: QVariant) !u32 {
var size: u32 = 0;
switch (variant) {
.int => {
size += 4;
},
.byte => {
size += 1;
},
.string => |*str| {
size += @intCast(u32, str.len);
// Null Terminator
size += 1;
},
else => {
size += 0;
},
}
return size;
}

View file

@ -17,7 +17,6 @@ pub fn get_bytearray(reader: anytype, allocator: *std.mem.Allocator) !std.ArrayL
var byteList = std.ArrayList(u8).init(allocator); var byteList = std.ArrayList(u8).init(allocator);
var length = try get_int(reader); var length = try get_int(reader);
var index: usize = 0; var index: usize = 0;
while (true) { while (true) {
if (index == length) return byteList; if (index == length) return byteList;

View file

@ -108,7 +108,7 @@ test "read/write byte variant" {
var byteList = std.ArrayList(u8).init(global_allocator); var byteList = std.ArrayList(u8).init(global_allocator);
defer byteList.deinit(); defer byteList.deinit();
try write.add_qvariant(byteList.writer(), @enumToInt(qvar.QVariantTypes.byte)); try write.add_qvariant_with_id(byteList.writer(), @enumToInt(qvar.QVariantTypes.byte));
try write.add_byte(byteList.writer(), 'a'); try write.add_byte(byteList.writer(), 'a');
var fBS = std.io.fixedBufferStream(byteList.items); var fBS = std.io.fixedBufferStream(byteList.items);
@ -121,7 +121,7 @@ test "read/write int variant" {
var byteList = std.ArrayList(u8).init(global_allocator); var byteList = std.ArrayList(u8).init(global_allocator);
defer byteList.deinit(); defer byteList.deinit();
try write.add_qvariant(byteList.writer(), @enumToInt(qvar.QVariantTypes.int_2)); try write.add_qvariant_with_id(byteList.writer(), @enumToInt(qvar.QVariantTypes.int_2));
try write.add_int(byteList.writer(), 1312); try write.add_int(byteList.writer(), 1312);
var fBS = std.io.fixedBufferStream(byteList.items); var fBS = std.io.fixedBufferStream(byteList.items);

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const qvar = @import("./qvariant.zig");
pub fn add_int(writer: anytype, number: u32) !void { pub fn add_int(writer: anytype, number: u32) !void {
try writer.writeIntBig(u32, number); try writer.writeIntBig(u32, number);
@ -29,9 +30,65 @@ pub fn add_stringlist(writer: anytype, strList: std.ArrayList([]const u8)) !void
} }
} }
// Call this and Then write your type // Call this and Then write your type
pub fn add_qvariant(writer: anytype, type_id: u32) !void { pub fn add_qvariant_with_id(writer: anytype, type_id: u32) !void {
try add_int(writer, type_id); try add_int(writer, type_id);
try add_byte(writer, 0); try add_byte(writer, 0);
} }
pub fn add_qvariant(writer: anytype, variant: qvar.QVariant) !void {
add_qvariant_with_id(writer, qvar.qvariant_type_id(variant));
switch (variant) {
.byte => |*out| {
return add_byte(writer, out);
},
.int_1, .int_2 => |*out| {
return add_int(writer, out);
},
.qmap => |*out| {
return add_qvariantmap(writer, out);
},
.string => |*out| {
return add_string(writer, out);
},
.stringlist => |*out| {
return add_stringlist(writer, out);
},
.bytearray => |*out| {
return add_bytearray(writer, out);
},
.short => |*out| {
return add_short(writer, out);
},
else => {
return 0;
},
}
}
pub fn add_qvariantmap(writer: anytype, map: std.StringHashMap(qvar.QVariant)) !void {
var size: u32 = 0;
var iterator = map.iterator();
while (iterator.next()) |entry| {
size += try qvar.qvariant_size(.{ .string = entry.key });
size += try qvar.qvariant_size(entry.value);
size += 4;
}
try add_int(writer, size + 4 + 1 + 4);
try add_int(writer, 8);
try add_byte(writer, 1);
try add_int(writer, map.count());
while (iterator.next()) |entry| {
size += try qvar.qvariant_size(.{ .string = entry.key });
size += try qvar.qvariant_size(entry.value);
size += 4;
}
std.debug.print("Size {d} !\n", .{size});
return;
}