new venti library.
diff --git a/src/libventi/fcall.c b/src/libventi/fcall.c
new file mode 100644
index 0000000..ace8962
--- /dev/null
+++ b/src/libventi/fcall.c
@@ -0,0 +1,230 @@
+#include <u.h>
+#include <libc.h>
+#include <venti.h>
+
+Packet*
+vtfcallpack(VtFcall *f)
+{
+	uchar buf[4];
+	Packet *p;
+
+	p = packetalloc();
+
+	buf[0] = f->type;
+	buf[1] = f->tag;
+	packetappend(p, buf, 2);
+
+	switch(f->type){
+	default:
+		werrstr("vtfcallpack: unknown packet type %d", f->type);
+		goto Err;
+
+	case VtRerror:
+		if(vtputstring(p, f->error) < 0)
+			goto Err;
+		break;
+
+	case VtTping:
+		break;
+
+	case VtRping:
+		break;
+
+	case VtThello:
+		if(vtputstring(p, f->version) < 0
+		|| vtputstring(p, f->uid) < 0)
+			goto Err;
+		buf[0] = f->strength;
+		buf[1] = f->ncrypto;
+		packetappend(p, buf, 2);
+		packetappend(p, f->crypto, f->ncrypto);
+		buf[0] = f->ncodec;
+		packetappend(p, buf, 1);
+		packetappend(p, f->codec, f->ncodec);
+		break;
+
+	case VtRhello:
+		if(vtputstring(p, f->sid) < 0)
+			goto Err;
+		buf[0] = f->rcrypto;
+		buf[1] = f->rcodec;
+		packetappend(p, buf, 2);
+		break;
+
+	case VtTgoodbye:
+		break;
+
+	case VtTread:
+		packetappend(p, f->score, VtScoreSize);
+		buf[0] = vttodisktype(f->dtype);
+		if(~buf[0] == 0)
+			goto Err;
+		buf[1] = 0;
+		buf[2] = f->count >> 8;
+		buf[3] = f->count;
+		packetappend(p, buf, 4);
+		break;
+
+	case VtRread:
+		packetconcat(p, f->data);
+		break;
+
+	case VtTwrite:
+		buf[0] = vttodisktype(f->dtype);
+		if(~buf[0] == 0)
+			goto Err;
+		buf[1] = 0;
+		buf[2] = 0;
+		buf[3] = 0;
+		packetappend(p, buf, 4);
+		packetconcat(p, f->data);
+		break;
+
+	case VtRwrite:
+		packetappend(p, f->score, VtScoreSize);
+		break;
+
+	case VtTsync:
+		break;
+
+	case VtRsync:
+		break;
+	}
+
+	return p;
+
+Err:
+	packetfree(p);
+	return nil;
+}
+
+int
+vtfcallunpack(VtFcall *f, Packet *p)
+{
+	uchar buf[4];
+
+	memset(f, 0, sizeof *f);
+
+	if(packetconsume(p, buf, 2) < 0)
+		return -1;
+
+	f->type = buf[0];
+	f->tag = buf[1];
+
+	switch(f->type){
+	default:
+		werrstr("vtfcallunpack: unknown bad packet type %d", f->type);
+		vtfcallclear(f);
+		return -1;
+
+	case VtRerror:
+		if(vtgetstring(p, &f->error) < 0)
+			goto Err;
+		break;
+
+	case VtTping:
+		break;
+
+	case VtRping:
+		break;
+
+	case VtThello:
+		if(vtgetstring(p, &f->version) < 0
+		|| vtgetstring(p, &f->uid) < 0
+		|| packetconsume(p, buf, 2) < 0)
+			goto Err;
+		f->strength = buf[0];
+		f->ncrypto = buf[1];
+		if(f->ncrypto){
+			f->crypto = vtmalloc(f->ncrypto);
+			if(packetconsume(p, buf, f->ncrypto) < 0)
+				goto Err;
+		}
+		if(packetconsume(p, buf, 1) < 0)
+			goto Err;
+		f->ncodec = buf[0];
+		if(f->ncodec){
+			f->codec = vtmalloc(f->ncodec);
+			if(packetconsume(p, buf, f->ncodec) < 0)
+				goto Err;
+		}
+		break;
+
+	case VtRhello:
+		if(vtgetstring(p, &f->sid) < 0
+		|| packetconsume(p, buf, 2) < 0)
+			goto Err;
+		f->rcrypto = buf[0];
+		f->rcodec = buf[1];
+		break;
+
+	case VtTgoodbye:
+		break;
+
+	case VtTread:
+		if(packetconsume(p, f->score, VtScoreSize) < 0
+		|| packetconsume(p, buf, 4) < 0)
+			goto Err;
+		f->dtype = vtfromdisktype(buf[0]);
+		if(~f->dtype == 0)
+			goto Err;
+		f->count = (buf[2] << 8) | buf[3];
+		break;
+
+	case VtRread:
+		f->data = packetalloc();
+		packetconcat(f->data, p);
+		break;
+
+	case VtTwrite:
+		if(packetconsume(p, buf, 4) < 0)
+			goto Err;
+		f->dtype = vtfromdisktype(buf[0]);
+		if(~f->dtype == 0)
+			goto Err;
+		f->data = packetalloc();
+		packetconcat(f->data, p);
+		break;
+
+	case VtRwrite:
+		if(packetconsume(p, f->score, VtScoreSize) < 0)
+			goto Err;
+		break;
+
+	case VtTsync:
+		break;
+
+	case VtRsync:
+		break;
+	}
+
+	if(packetsize(p) != 0)
+		goto Err;
+
+	return 0;
+
+Err:
+	werrstr("bad packet");
+	return -1;
+}
+
+void
+vtfcallclear(VtFcall *f)
+{
+	vtfree(f->error);
+	f->error = nil;
+	vtfree(f->uid);
+	f->uid = nil;
+	vtfree(f->sid);
+	f->sid = nil;
+	vtfree(f->version);
+	f->version = nil;
+	vtfree(f->crypto);
+	f->crypto = nil;
+	vtfree(f->codec);
+	f->codec = nil;
+	vtfree(f->auth);
+	f->auth = nil;
+	packetfree(f->data);
+	f->auth = nil;
+}