cdef extern from "Python.h":
object PyString_FromStringAndSize(char *s, int len)
cdef extern from "netinet/in.h":
ctypedef struct in_addr:
char* s_addr # don't actually use it
ctypedef struct sockaddr_in:
in_addr sin_addr
char *inet_ntoa(in_addr)
cdef extern from "sys/time.h":
cdef struct timeval:
int tv_sec # or use long? mac uses int32_t
int tv_usec
# why can't this just use <> too?
cdef extern from "zephyr/zephyr.h":
ctypedef int Code_t
Code_t ZInitialize()
ctypedef enum ZNotice_Kind_t:
UNSAFE
UNACKED
ACKED
HMACK
HMCTL
SERVACK
SERVNAK
CLIENTACK
STAT
ctypedef struct ZUnique_Id_t:
in_addr zuid_addr
timeval tv
ctypedef struct ZNotice_t:
ZNotice_Kind_t z_kind
unsigned short z_port
timeval z_time
ZUnique_Id_t z_uid
#define z_sender_addr z_uid.zuid_addr
char *z_class
char *z_class_inst
char *z_opcode
char *z_sender
char *z_recipient
char *z_default_format
char *z_message
int z_message_len
ctypedef Code_t (*Z_AuthProc) (ZNotice_t*, char *, int, int *)
Code_t ZMakeAuthentication(ZNotice_t*, char *,int, int*)
Code_t ZSendNotice(ZNotice_t *znt, Z_AuthProc)
Code_t ZReceiveNotice(ZNotice_t *, sockaddr_in *)
ctypedef struct ZSubscription_t:
char *zsub_recipient
char *zsub_class
char *zsub_classinst
Code_t ZSubscribeTo(ZSubscription_t *sublist, int nitems, unsigned int port)
Code_t ZSubscribeToSansDefaults(ZSubscription_t *sublist, int nitems, unsigned int port)
Code_t ZUnsubscribeTo(ZSubscription_t *sublist, int nitems, unsigned int port)
Code_t ZCancelSubscriptions(unsigned int port)
char* error_message(int)
ctypedef struct ZAsyncLocateData_t:
char *user
# ZUnique_Id_t uid
char *version
Code_t ZRequestLocations(char *, ZAsyncLocateData_t *, ZNotice_Kind_t, Z_AuthProc)
Code_t ZParseLocations(ZNotice_t *notice, ZAsyncLocateData_t *zald, int *nlocs, char **user)
ctypedef struct ZLocations_t:
char *host
char *time
char *tty
Code_t ZGetLocations(ZLocations_t *location, int *numlocs)
#define ZERR_NOMORELOCS (-772103667L)
ctypedef enum dummy_zerr_t:
ZERR_NOLOCATIONS
ZERR_NOMORELOCS
# support for a receiving client
Code_t ZOpenPort(unsigned short *port)
char *ZGetSender()
int ZPending()
#define ZGetFD() __Zephyr_fd
int __Zephyr_fd
#define ZGetRealm() __Zephyr_realm
char __Zephyr_realm[]
class ComErrException(Exception):
pass
cdef comret(Code_t ret):
if ret != 0:
raise ComErrException(error_message(ret))
def zinit(force=[]):
cdef Code_t ret
if len(force):
return
force.append(None)
ret = ZInitialize()
print "init done"
comret(ret)
def openport():
cdef Code_t ret
cdef unsigned short port
port = 0
ret = ZOpenPort(&port)
comret(ret)
return port
def zgetfd():
return __Zephyr_fd
def zgetrealm():
return __Zephyr_realm
cdef class CNotice:
cdef ZNotice_t znt
def __init__(self, zclass, zinst, opcode, sender, recip, deffmt):
zinit()
self.znt.z_class = zclass
print "zclass set"
self.znt.z_class_inst = zinst
self.znt.z_opcode = opcode
self.znt.z_sender = sender
self.znt.z_recipient = recip
self.znt.z_default_format = deffmt
self.znt.z_kind = ACKED
self.znt.z_port = 0
def send(self, sig, message, auth = None):
msgbuf = sig + chr(0) + message
cdef Code_t ret
cdef Z_AuthProc zauth
self.znt.z_message = msgbuf
self.znt.z_message_len = len(msgbuf)
zauth = NULL
if auth:
zauth = ZMakeAuthentication
ret = ZSendNotice(&self.znt, zauth)
self.znt.z_message = NULL
comret(ret)
def zreceive(self):
cdef Code_t ret
ret = ZReceiveNotice(&self.znt, NULL)
comret(ret)
message = ""
mlen = self.znt.z_message_len
if mlen > 0 and self.znt.z_message[mlen-1] == 0:
mlen = mlen - 1
if mlen > 0:
message = PyString_FromStringAndSize(self.znt.z_message, mlen)
timet = self.znt.z_time.tv_sec + self.znt.z_time.tv_usec / 1e6
addr = inet_ntoa(self.znt.z_uid.zuid_addr)
return self.znt.z_class, self.znt.z_class_inst, self.znt.z_opcode, self.znt.z_sender, self.znt.z_recipient, self.znt.z_default_format, message, timet, addr
class Notice(CNotice):
def __init__(self, zclass, zinst, opcode, sender, recip, deffmt):
self.zclass = zclass
self.zinst = zinst
self.opcode = opcode
self.sender = sender
self.recip = recip
self.deffmt = deffmt
CNotice.__init__(self, self.zclass, self.zinst, self.opcode, self.sender, self.recip, self.deffmt)
def pending(self):
return ZPending()
def receive(self):
self.zclass, self.zinst, self.opcode, self.sender, self.recip, self.deffmt, self.message, self.time, self.sender_addr = self.zreceive()
cdef class CSubscription:
cdef ZSubscription_t zsub
def __init__(self, zrecip, zclass, zinst):
self.zsub.zsub_recipient = zrecip
self.zsub.zsub_class = zclass
self.zsub.zsub_classinst = zinst
# consider using property/__get__/__set__ here?
def sub(self, port):
cdef Code_t ret
zinit()
ret = ZSubscribeToSansDefaults(&self.zsub, 1, port)
if ret != 0:
raise ComErrException(error_message(ret))
def unsub(self, port):
cdef Code_t ret
zinit()
ret = ZUnsubscribeTo(&self.zsub, 1, port)
if ret != 0:
raise ComErrException(error_message(ret))
def cancel(self, port):
cdef Code_t ret
zinit()
ret = ZCancelSubscriptions(port)
if ret != 0:
raise ComErrException(error_message(ret))
cdef class CAsyncLocation:
cdef ZAsyncLocateData_t ald
def request(self, user):
cdef Code_t ret
ret = ZRequestLocations(user, &self.ald, UNSAFE, ZMakeAuthentication)
comret(ret)
cdef class LocNotice(CNotice):
def parseloc(self):
cdef Code_t ret
cdef int numlocs
cdef char *whichuser
ret = ZParseLocations(&self.znt, NULL, &numlocs, &whichuser)
comret(ret)
# turns out we don't care how many, we can just go until ZGetLocations gives ZERR_NOMORELOCS...
return whichuser
cdef class CLocation:
cdef ZLocations_t loc
def getloc(self):
cdef Code_t ret
cdef int one
one = 1
ret = ZGetLocations(&self.loc, &one)
if ret == 0:
return (self.loc.host, self.loc.time, self.loc.tty)
if ret == ZERR_NOMORELOCS:
return None
if ret == ZERR_NOLOCATIONS:
return None
comret(ret)
def sender():
return ZGetSender()