Created
January 15, 2015 04:48
-
-
Save Laeeth/a4060e62fab5e3a1ea0d to your computer and use it in GitHub Desktop.
Using linux sockets to talk to dovecot doveadm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module doveadm; | |
import std.stdio; | |
import std.socket; | |
import std.string; | |
import std.array; | |
import std.c.linux.socket; | |
import core.sys.posix.sys.un; | |
import std.conv; | |
enum doveadmSocketPath= "/var/run/dovecot/doveadm-server"; | |
private string tabify(string s) | |
{ | |
string s2=""; | |
foreach(char c;s) | |
if (c=='\t') | |
s2~=r"\t"; | |
else | |
s2~=c; | |
return s2; | |
} | |
private string[] detab(string s) | |
{ | |
return s.split("\t"); | |
} | |
class UnixAddress: Address | |
{ | |
private: | |
sockaddr_un sun; | |
this() | |
{ | |
} | |
public: | |
override @property sockaddr* name() | |
{ | |
return cast(sockaddr*)&sun; | |
} | |
override @property const(sockaddr)* name() const | |
{ | |
return cast(const(sockaddr)*)&sun; | |
} | |
override @property socklen_t nameLen() const | |
{ | |
return cast(socklen_t) sun.sizeof; | |
} | |
this(in char[] path) | |
{ | |
sun.sun_family = AF_UNIX; | |
sun.sun_path.ptr[0..path.length] = cast(byte[])path; | |
sun.sun_path.ptr[path.length] = 0; | |
} | |
@property string path() const | |
{ | |
return to!string(sun.sun_path.ptr); | |
} | |
override string toString() const | |
{ | |
return path; | |
} | |
} | |
struct DoveADMClient | |
{ | |
Socket sock; | |
string path; | |
string openMessage = "VERSION\tdoveadm-server\t1\t0\n"; | |
this(string path) | |
{ | |
this.path=path; | |
this.sock=new Socket(AddressFamily.UNIX, SocketType.STREAM, cast(ProtocolType)AF_UNIX); | |
auto z=new doveadm.UnixAddress(path); | |
sock.connect(new doveadm.UnixAddress(cast(char[])path)); | |
sock.setOption(SocketOptionLevel.SOCKET,SocketOption.RCVTIMEO,dur!"msecs"(800)); | |
writefln("* is it alive: %s", sock.getErrorText()); | |
sock.setOption(SocketOptionLevel.SOCKET,SocketOption.SNDTIMEO,dur!"msecs"(800)); | |
writefln("* is it alive: %s", sock.getErrorText()); | |
sock.send(cast(ubyte[])openMessage); | |
writefln("* is it alive: %s", sock.getErrorText()); | |
writefln("* sent handshake - waiting for reply"); | |
auto ret=listen(); | |
writefln("* got reply: %s",ret); | |
if (ret.indexOf("+")==-1) | |
throw new Exception("doveadm did not return the handshake"); | |
writef(ret); | |
} | |
~this() | |
{ | |
sock.shutdown(SocketShutdown.BOTH); | |
sock.close(); | |
} | |
string[] sendCommand(string s) | |
{ | |
if (sock is null) | |
throw new Exception("socket must be open"); | |
if (sock.send(s~"\n")==0) | |
{ | |
writefln("* couldnt send any bytes"); | |
return null; | |
} | |
return(detab(listen())); | |
} | |
string listen() | |
{ | |
string s; | |
ubyte[1024*1024] buf; | |
while(true) | |
{ | |
auto result=sock.receive(buf); // flags | |
writefln("* result: %s",result); | |
if (result<=0) | |
return s; | |
s~=removechars(cast(string)(buf[0..result]),"\n"); | |
} | |
assert(0); | |
} | |
string[] getUserGuid(string u) | |
{ | |
return sendCommand("\t"~u~"\t"~"mailbox status\tguid\t*"); | |
} | |
stringp[] | |
} | |
void main(string[] args) | |
{ | |
auto doveadm=DoveADMClient(doveadmSocketPath); | |
writeln(doveadm.sendCommand("\[email protected]\tmailbox list")); | |
writeln(doveadm.getUserGuid("[email protected]")); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment