diff options
author | Matěj Cepl <mcepl@cepl.eu> | 2015-02-05 09:47:10 +0100 |
---|---|---|
committer | Matěj Cepl <mcepl@cepl.eu> | 2015-02-05 09:47:10 +0100 |
commit | c912d0844a01f67ae1c95c8725526ca8b6751a89 (patch) | |
tree | 6d4b60260bde837a1bcff6f2ff4347a1c5e83248 /jacs | |
parent | 295b95085f3d7cf7d405771e81bb33902838286e (diff) | |
download | jacc-c912d0844a01f67ae1c95c8725526ca8b6751a89.tar.gz |
Diffstat (limited to 'jacs')
-rw-r--r-- | jacs/dat.c | 89 | ||||
-rw-r--r-- | jacs/dat.h | 10 | ||||
-rw-r--r-- | jacs/jacs.c | 231 | ||||
-rw-r--r-- | jacs/jacs.h | 33 | ||||
-rw-r--r-- | jacs/mkfile | 24 | ||||
-rw-r--r-- | jacs/mkfile.plan9port | 25 | ||||
-rw-r--r-- | jacs/recv.c | 292 | ||||
-rw-r--r-- | jacs/recv.h | 8 | ||||
-rw-r--r-- | jacs/roster.c | 102 | ||||
-rw-r--r-- | jacs/roster.h | 33 | ||||
-rw-r--r-- | jacs/xmlpull.h | 51 |
11 files changed, 898 insertions, 0 deletions
diff --git a/jacs/dat.c b/jacs/dat.c new file mode 100644 index 0000000..094f27f --- /dev/null +++ b/jacs/dat.c @@ -0,0 +1,89 @@ +/* + * Copy me if you can. + * by 20h + */ + +#include <u.h> +#include <libc.h> +#include "dat.h" + +void * +reallocj(void *p, int s, short d) +{ + p = realloc(p, s); + if(p == nil) + sysfatal("realloc: %r"); + + if(d != 0) + memset(p, 0, s); + + return (void *)p; +} + +char * +setwindowlbl(char *w) +{ + int s; + + s = open("/dev/label", OWRITE); + if(s < 0) + return nil; + + write(s, w, strlen(w)); + + close(s); + return w; +} + +char * +getwindowlbl(void) +{ + int s; + char *ret; + short i; + + s = open("/dev/label", OREAD); + if(s < 0) + return nil; + + i = 0; + ret = malloc(0); + while(realloc(ret, ++i) != nil && read(s, &ret[i - 1], 1) > 0 && + i < 513); + + ret[i - 1] = '\0'; + + close(s); + return ret; +} + +char * +mktmstmp(char bord, char bord_e) +{ + Tm *tim; + char *ret; + + ret = reallocj(nil, 32, 2); + tim = localtime(time(0)); + snprint(ret, 31, "%c%.2d:%.2d%c ", bord, tim->hour, tim->min, bord_e); + + return ret; +} + +char * +printjid(char *user, char *serv, char *reso) +{ + char *ret; + int i; + + if(user == nil || serv == nil) + return nil; + + i = strlen(user) + strlen(serv) + 3 + ((reso != nil) ? strlen(reso) : 0); + + ret = reallocj(nil, i, 2); + snprint(ret, i, "%s@%s%s%s", user, serv, (reso != nil) ? "/" : "\0", + ((reso != nil) ? reso : "")); + + return ret; +} diff --git a/jacs/dat.h b/jacs/dat.h new file mode 100644 index 0000000..fca069f --- /dev/null +++ b/jacs/dat.h @@ -0,0 +1,10 @@ +#ifndef JDAT_H +#define JDAT_H + +void *reallocj(void *p, int s, short d); +char *setwindowlbl(char *w); +char *getwindowlbl(void); +char *mktmstmp(char bord, char bord_e); +char *printjid(char *user, char *serv, char *reso); + +#endif diff --git a/jacs/jacs.c b/jacs/jacs.c new file mode 100644 index 0000000..21f3139 --- /dev/null +++ b/jacs/jacs.c @@ -0,0 +1,231 @@ +/* + * Copy me if you can. + * by 20h + */ + +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <mp.h> +#include <libsec.h> +#include "xmlpull.h" +#include "jacs.h" +#include "dat.h" +#include "roster.h" +#include "recv.h" + +#define NAME "jacs - Jabber Service Registry for Plan9" +#define VERSION "2nd ed" +#define OS "Plan9 4th ed" + +int +xmljacc(int sock) +{ + return fprint(sock, "<?xml version=\"1.0\"?>\n"); +} + +int +loginjacc(int sock, char *serv) +{ + return fprint(sock, "<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\"" + " xmlns=\"jabber:client\" to=\"%s\">\n", serv); +} + +int +userjacc(int sock, char *user, char *pass, char *res) +{ + return fprint(sock, "<iq type=\"set\" id=\"auth_1\">\n" + "<query xmlns=\"jabber:iq:auth\">\n" + "<username>%s</username>\n" + "<password>%s</password>\n" + "<resource>%s</resource>\n" + "</query>\n" + "</iq>\n", user, pass, res); +} + +int +presencejacc(int sock, char *stat, char *show, char *from, char *to) +{ + return fprint(sock, "<presence%s%s%s%s%s%s>\n" + "<show>%s</show>\n" + "<status>%s</status>\n" + "<priority>1</priority>\n" + "</presence>\n", (from != nil) ? " from=\"" : "", + (from != nil) ? from : "", + (from != nil) ? "\"" : "", + (to != nil) ? " to=\"" : "", + (to != nil) ? to : "", + (to != nil) ? "\"" : "", + (show != nil) ? show : "", + (stat != nil) ? stat : ""); +} + +int +versionjacc(int sock, char *from, char *to, char *id) +{ + return fprint(sock, "<iq from=\"%s\" type=\"result\" id=\"%s\" to=\"%s\">\n" + "<query xmlns=\"jabber:iq:version\">\n" + "<name>" NAME "</name>\n" + "<version>" VERSION "</version>\n" + "<os>" OS "</os>\n" + "</query>\n" + "</iq>\n", from, id, to); +} + +int +featuresjacc(int sock, char *from, char *to, char *id) +{ + return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n" + "<query xmlns=\"http://jabber.org/protocol/disco#info\">\n" + "</query>\n" + "</iq>\n", from, to, id); +} + +int +answersjacc(int sock, char *who, char *t, char *id, ilist *l) +{ + fprint(sock, "<iq type=\"set\" to=\"%s\" id=\"%s\">\n" + "<query xmlns=\"%s\">\n", who, id, t); + for(; l; l = l->n) + fprint(sock, "<%s>%s</%s>\n", l->name, l->val, l->name); + + return fprint(sock, "</query>\n" + "</iq>\n"); +} + +int +xmlnsjacc(int sock, char *who, char *t, char *id) +{ + return fprint(sock, "<iq type=\"get\" to=\"%s\" id=\"%s\">\n" + "<query xmlns=\"%s\"/>\n" + "</iq>\n", who, id, t); +} + +int +xmlnsnegjacc(int sock, char *who, char *t, char* id) +{ + return fprint(sock, "<iq type=\"set\" to=\"%s\" id=\"%s\">\n" + "<query xmlns=\"%s\">\n" + "<remove/>\n" + "</query>\n" + "</iq>\n", who, id, t); +} + +void +usage(void) +{ + print("usage: jacs [-dtu] [-e dest] [-s tosrv] [-r res] net!server!port\n"); + exits(0); +} + +int +main(int argc, char *argv[]) +{ + char *server, *user, *lbl, *b, *dest, *buf, *toserver; + int sock, ts, tls, debug, unreg; + UserPasswd *i; + TLSconn conn; + jabberc *me; + + tls = 0; + b = nil; + dest = nil; + unreg = 0; + debug = 0; + toserver = nil; + + ARGBEGIN { + case 't': + tls = 1; + break; + case 'r': + b = EARGF(usage()); + break; + case 'e': + dest = EARGF(usage()); + break; + case 'u': + unreg = 1; + break; + case 'd': + debug = 1; + break; + case 's': + toserver = EARGF(usage()); + break; + default: + usage(); + } ARGEND; + + if(argc < 1 || dest == nil) + usage(); + server = strdup(argv[0]); + + lbl = getwindowlbl(); + user = reallocj(nil, strlen(server) + 9, 2); + snprint(user, strlen(server) + 8, "jacs - %s", server); + setwindowlbl(user); + free(user); + + i = auth_getuserpasswd(auth_getkey, "proto=pass server=%s service=jabber", server); + if(i == nil) + sysfatal("auth_getuserpasswd: %r"); + + sock = dial(netmkaddr(server, "tcp", tls ? "5223" : "5222"), 0, 0, 0); + if(sock < 0) + sysfatal("dial: &r"); + + if(tls){ + ts = tlsClient(sock, &conn); + if(ts < 0) + sysfatal("tlsClient: %r"); + sock = ts; + + if(conn.cert != nil) + free(conn.cert); + } + + buf = strchr(server, '!'); + if(buf != nil) { + *buf++ = '\0'; + user = strchr(buf, '!'); + if(user != nil) + *user = '\0'; + user = strdup(buf); + free(server); + server = user; + } + + if(toserver == nil) + toserver = server; + + me = mkjabberc(); + me->dest = strdup(dest); + me->show = strdup("Online"); + me->stat = strdup("Online"); + me->name = strdup(i->user); + me->serv = strdup(toserver); + + if(b != nil) + me->reso = strdup(b); + else + me->reso = strdup("Plan9-Service"); + me->jid = printjid(me->name, me->serv, me->reso); + me->debug = debug; + me->unreg = unreg; + + free(buf); + + if(recvjacc(sock, me, i->passwd) < 0) + perror("recv_jacc"); + + if(lbl != nil){ + setwindowlbl(lbl); + lbl = nil; + free(lbl); + } + + freejabberc(me); + exits(0); + return 0; +} diff --git a/jacs/jacs.h b/jacs/jacs.h new file mode 100644 index 0000000..2475a23 --- /dev/null +++ b/jacs/jacs.h @@ -0,0 +1,33 @@ +#ifndef JACS_H +#define JACS_H + +#include "roster.h" + +enum { + NONE = 0x00, + STREAM, + AUTH, + ERROR, + MESSAGE, + MESSAGE_INNER, + IQ, + IQ_INNER, + IQ_ERROR, + IQ_REGISTER, + IQ_REGISTER_INST, + IQ_REGISTER_INNE, + END +}; + +int xmljacc(int sock); +int loginjacc(int sock, char *serv); +int userjacc(int sock, char *user, char *pass, char *res); +int versionjacc(int sock, char *from, char *to, char *id); +int presencejacc(int sock, char *stat, char *show, char *from, char *to); +int featuresjacc(int sock, char *from, char *to, char *id); +int answersjacc(int sock, char *who, char *t, char *id, ilist *l); +int xmlnsjacc(int sock, char *who, char *t, char *id); +int xmlnsnegjacc(int sock, char *who, char *t, char *id); + +#endif + diff --git a/jacs/mkfile b/jacs/mkfile new file mode 100644 index 0000000..eeebb9a --- /dev/null +++ b/jacs/mkfile @@ -0,0 +1,24 @@ +</$objtype/mkfile +BIN=/$objtype/bin + +TARG=jacs +OFILES=\ + dat.$O\ + roster.$O\ + recv.$O\ + jacs.$O\ + +HFILES=\ + roster.h\ + dat.h\ + recv.h\ + jacs.h\ + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + ${TARG:%=/386/bin/%}\ + +</sys/src/cmd/mkone + diff --git a/jacs/mkfile.plan9port b/jacs/mkfile.plan9port new file mode 100644 index 0000000..0003be3 --- /dev/null +++ b/jacs/mkfile.plan9port @@ -0,0 +1,25 @@ +</$PLAN9/src/mkhdr +BIN=$PLAN9/bin + +LDFLAGS=-lxmlpull +CFLAGS=-DPLAN9PORT +TARG=jacc +OFILES=\ + dat.$O\ + roster.$O\ + recv.$O\ + jacs.$O\ + +HFILES=\ + roster.h\ + dat.h\ + recv.h\ + jacs.h\ + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + ${TARG:%=/386/bin/%}\ + +<$PLAN9/src/mkone diff --git a/jacs/recv.c b/jacs/recv.c new file mode 100644 index 0000000..63b1b91 --- /dev/null +++ b/jacs/recv.c @@ -0,0 +1,292 @@ +/* + * Copy me if you can. + * by 20h + */ + +#include <u.h> +#include <libc.h> +#include "xmlpull.h" +#include "jacs.h" +#include "dat.h" +#include "roster.h" + +char * +getline(void) +{ + char *ret; + int l; + + l = -1; + ret = reallocj(nil, 1025, 2); + + while(read(0, &ret[++l], 1) && l < 1024) + if(ret[l] == '\n') + break; + ret[l] = '\0'; + + return ret; +} + +void +askanswers(ilist *i, char *tmstmp) +{ + ilist *ac; + char *val; + + ac = i; + while(ac != nil){ + print("%s%s[%s] = ", tmstmp, ac->name, (ac->val != nil) ? ac->val : ""); + val = getline(); + if(ac->val == nil) + ac->val = val; + else { + if(*val != '\0'){ + free(ac->val); + ac->val = val; + } else + free(val); + } + ac = ac->n; + } + + return; +} + +int +recvjacc(int sock, jabberc *me, char *pass) +{ + xmlpull *x, *b; + char *id, *to, *from, *tmstmp, st, *type; + ilist *ac; + + type = nil; + id = nil; + from = nil; + to = nil; + st = NONE; + ac = nil; + + if(xmljacc(sock) < 0) + return -1; + if(loginjacc(sock, me->serv) < 0) + return -1; + + x = openxmlpull(sock); + while((b = nextxmlpull(x)) != nil && st != END){ + tmstmp = mktmstmp('(', ')'); + switch(b->ev){ + case START_DOCUMENT: + if(me->debug) + print("Start.\n"); + st = NONE; + break; + case START_TAG: + if(me->debug) + print("Tag: %s\n", x->na); + if(!strcmp(x->na, "stream:stream")){ + st = STREAM; + break; + } + if(!strcmp(x->na, "stream:error")){ + st = ERROR; + break; + } + if(st == ERROR){ + if(strcmp(x->na, "text")) + fprint(2, "%serror: %s\n", tmstmp, x->na); + break; + } + if(!strcmp(x->na, "iq")){ + st = IQ; + break; + } + if(!strcmp(x->na, "error") && st == IQ){ + st = IQ_ERROR; + break; + } + if(st == IQ_ERROR){ + print("IQ-Error: %s\n", x->na); + break; + } + if(!strcmp(x->na, "query") && st == IQ){ + st = IQ_INNER; + break; + } + if(!strcmp(x->na, "instructions") && st == IQ_REGISTER){ + st = IQ_REGISTER_INST; + break; + } + if(!strcmp(x->na, "query") && st == IQ_REGISTER) + break; + if(st == IQ_REGISTER){ + st = IQ_REGISTER_INNE; + me->list = addilist(me->list, x->na, nil); + ac = lastilist(me->list); + break; + } + break; + case START_END_TAG: + if(me->debug) + print("Startend: %s\n", x->na); + if(st == IQ_REGISTER){ + if(!strcmp(x->na, "registered")){ + print("%sAlready registerd.\n", tmstmp); + break; + } + if(strcmp(x->na, "remove")) + me->list = addilist(me->list, x->na, nil); + break; + } + if(st == ERROR){ + fprint(2, "%serror: %s\n", tmstmp, x->na); + break; + } + break; + case TEXT: + if(me->debug) + print("Text: %s\n", x->na); + switch(st){ + case IQ_REGISTER_INST: + print("%s %s\n", tmstmp, x->na); + break; + case IQ_REGISTER_INNE: + ac->val = strdup(x->na); + break; + default: + break; + } + break; + case ATTR: + if(me->debug) + print("Attr: %s = %s\n", x->na, x->va); + switch(st){ + case STREAM: + if(!strcmp(x->na, "id")){ + st = NONE; + if(userjacc(sock, me->name, pass, me->reso) < 0) { + memset(pass, 0, strlen(pass)); + st = AUTH; + break; + } + } + break; + case IQ: + if(!strcmp(x->na, "id")){ + if(!strcmp(x->va, "auth_1")) { + presencejacc(sock, me->stat, me->show, me->jid, nil); + if(me->unreg) + xmlnsnegjacc(sock, me->dest, "jabber:iq:register", "service_1"); + else + xmlnsjacc(sock, me->dest, "jabber:iq:register", "service_0"); + } + if(!strcmp(x->va, "service_0")) + st = IQ_REGISTER; + id = strdup(x->va); + } + if(!strcmp(x->na, "from")) + from = strdup(x->va); + if(!strcmp(x->na, "to")) + to = strdup(x->va); + if(!strcmp(x->na, "type")) + type = strdup(x->va); + break; + case IQ_INNER: + if(!strcmp(x->na, "xmlns")){ + if(!strcmp(x->va, "jabber:iq:version")) { + if(!strcmp(to, me->jid)){ + print("%s%s:\n", tmstmp, from); + break; + } else + versionjacc(sock, me->jid, from, id); + break; + } + if(!strcmp(x->va, "http://jabber.org/protocol/disco#info")) + if(!strcmp(me->jid, to)) + featuresjacc(sock, to, from, id); + + } + break; + default: + break; + } + break; + case END_TAG: + if(me->debug) + print("Endtag: %s\n", x->na); + if(!strcmp(x->na, "stream:stream")){ + st = END; + break; + } + if(!strcmp(x->na, "stream:error") && st == ERROR){ + st = NONE; + break; + } + if(st == ERROR) + break; + if(!strcmp(x->na, "iq") && (st == IQ || st == IQ_REGISTER)){ + st = NONE; + if(type != nil){ + if(!strcmp(type, "result") && !strcmp(id, "service_1")){ + print("%sSuccess.\n", tmstmp); + st = END; + } + free(type); + } + if(from != nil) + free(from); + if(to != nil) + free(to); + if(id != nil) + free(id); + from = nil; + to = nil; + id = nil; + type = nil; + break; + } + if(!strcmp(x->na, "error") && st == IQ_ERROR){ + st = IQ; + break; + } + if(!strcmp(x->na, "query") && st == IQ_INNER){ + st = IQ; + break; + } + if(!strcmp(x->na, "query") && st == IQ_REGISTER){ + st = IQ; + if(me->list != nil){ + askanswers(me->list, tmstmp); + answersjacc(sock, me->dest, "jabber:iq:register", "service_1", me->list); + freeilist(me->list); + me->list = nil; + } + break; + } + if(!strcmp(x->na, "instructions") && st == IQ_REGISTER_INST){ + st = IQ_REGISTER; + break; + } + if(st == IQ_REGISTER_INNE){ + st = IQ_REGISTER; + break; + } + break; + case END_DOCUMENT: + if(me->debug) + print("Documentend.\n"); + st = END; + break; + default: + print("Please contact the xmlpull author about this. %x\n", b->ev); + st = END; + break; + } + free(tmstmp); + } + + if(id != nil) + free(id); + freexmlpull(x); + + return 0; +} diff --git a/jacs/recv.h b/jacs/recv.h new file mode 100644 index 0000000..94f09ff --- /dev/null +++ b/jacs/recv.h @@ -0,0 +1,8 @@ +#ifndef RECV_H +#define RECV_H + +char *getline(void); +void askanswer(ilist *i, char *tmstmp); +int recvjacc(int sock, jabberc *me, char *pass); + +#endif diff --git a/jacs/roster.c b/jacs/roster.c new file mode 100644 index 0000000..d4cc372 --- /dev/null +++ b/jacs/roster.c @@ -0,0 +1,102 @@ +/* + * Copy me if you can. + * by 20h + */ + +#include <u.h> +#include <libc.h> +#include "dat.h" +#include "roster.h" + +void +freeilist(ilist *i) +{ + while(i != nil){ + if(i->name != nil) + free(i->name); + if(i->val != nil) + free(i->val); + if(i->n != nil){ + i = i->n; + free(i->p); + } else { + free(i); + i = nil; + } + } +} + + +void +freejabberc(jabberc *j) +{ + if(j != nil){ + if(j->stat != nil) + free(j->stat); + if(j->name != nil) + free(j->name); + if(j->reso != nil) + free(j->reso); + if(j->serv != nil) + free(j->serv); + if(j->jid != nil) + free(j->jid); + if(j->show != nil) + free(j->show); + if(j->dest != nil) + free(j->dest); + if(j->list != nil) + freeilist(j->list); + free(j); + } + return; +} + +jabberc * +mkjabberc(void) +{ + return reallocj(nil, sizeof(jabberc), 2); +} + +ilist * +lastilist(ilist *i) +{ + if(i != nil) + while(i->n != nil) + i = i->n; + + return i; +} + +ilist * +mkilist(char *name, char *val) +{ + ilist *ret; + + ret = reallocj(nil, sizeof(ilist), 2); + if(name != nil) + ret->name = strdup(name); + if(val != nil) + ret->val = strdup(val); + + return ret; +} + +ilist * +addilist(ilist *i, char *name, char *val) +{ + ilist *ret; + + ret = lastilist(i); + if(ret == nil) + return mkilist(name, val); + else { + ret->n = mkilist(name, val); + ret->n->p = ret; + } + ret->n->n = nil; + + return i; +} + +
\ No newline at end of file diff --git a/jacs/roster.h b/jacs/roster.h new file mode 100644 index 0000000..75d49b5 --- /dev/null +++ b/jacs/roster.h @@ -0,0 +1,33 @@ +#ifndef ROSTER_H +#define ROSTER_H + +typedef struct ilist ilist; +struct ilist { + char *name; + char *val; + ilist *p; + ilist *n; +}; + +typedef struct jabberc jabberc; +struct jabberc { + char *stat; + char *show; + char *name; + char *reso; + char *serv; + char *jid; + char *dest; + ilist *list; + int debug; + int unreg; +}; + +void freeilist(ilist *i); +void freejabberc(jabberc *j); +jabberc *mkjabberc(void); +ilist *lastilist(ilist *i); +ilist *mkilist(char *name, char *val); +ilist *addilist(ilist *i, char *name, char *val); + +#endif diff --git a/jacs/xmlpull.h b/jacs/xmlpull.h new file mode 100644 index 0000000..5a008f4 --- /dev/null +++ b/jacs/xmlpull.h @@ -0,0 +1,51 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifdef nil +#pragma lib "libxmlpull.a" +#endif + +#ifndef XMLPULL_H +#define XMLPULL_H + +#ifndef nil +#define nil NULL +#define print printf +#define snprint snprintf +#define exits return +#endif + +enum { + START_DOCUMENT = 0x0, + START_TAG, + START_END_TAG, + TEXT, + TEXT_C, + ATTR, + END_TAG, + END_TAG_S, + END_TAG_N, + END_DOCUMENT, +}; + +typedef struct xmlpull xmlpull; +struct xmlpull { + int fd; + char ev; + char nev; + char *lm; + char *na; + char *va; + int la; + int lv; + int ln; +}; + +void freexmlpull(xmlpull *x); +xmlpull *openxmlpull(int fd); +xmlpull *nextxmlpull(xmlpull *x); +xmlpull *writexmlpull(xmlpull *x); + +#endif |