summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jacc-paste.c757
-rw-r--r--jacc.c820
-rw-r--r--jacc.tarbin0 -> 102400 bytes
3 files changed, 1577 insertions, 0 deletions
diff --git a/jacc-paste.c b/jacc-paste.c
new file mode 100644
index 0000000..6874b93
--- /dev/null
+++ b/jacc-paste.c
@@ -0,0 +1,757 @@
+/*
+ * 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 "jacc.h"
+#include "dat.h"
+#include "roster.h"
+#include "recv.h"
+
+#define NAME "jacc - Jabber Client for Plan9"
+#define VERSION "3rd ed"
+#define OS "Plan 9 4th ed"
+
+extern int doignore;
+
+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
+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 == nil) ? "" : 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"
+ "<identity category=\"client\" type=\"pc\"/>\n"
+ "<feature var=\"jabber:iq:time\"/>\n"
+ "<feature var=\"jabber:iq:version\"/>\n"
+ "<feature var=\"http://jabber.org/protocol/muc\"/>\n"
+ "</query>\n"
+ "</iq>\n", from, to, (id == nil) ? "" : id);
+}
+
+int
+timejacc(int sock, char *from, char *to, char *id)
+{
+ Tm *lo, *gm;
+
+ lo = localtime(time(0));
+ gm = gmtime(time(0));
+
+ return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n"
+ "<query xmlns=\"jabber:iq:time\">\n"
+ "<utc>%.4d%.2d%.2dT%.2d:%.2d:%.2d</utc>\n"
+ "<display>%s %s %.2d %.2d:%.2d:%.2d %.4d</display>\n"
+ "<tz>%s</tz>\n"
+ "</query>\n"
+ "</iq>\n", from, to, (id == nil) ? "" : id, gm->year + 1900,
+ gm->mon + 1, gm->mday, gm->hour, gm->min,
+ gm->sec, getday(lo->wday), getmonth(lo->mon),
+ lo->mday, lo->hour, lo->min, lo->sec,
+ lo->year + 1900, lo->zone);
+}
+
+int
+lastjacc(int sock, char *from, char *to, char *id, int d)
+{
+ return fprint(sock, "<iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\">\n"
+ "<query xmlns=\"jabber:iq:last\" seconds=\"%d\"/>\n"
+ "</iq>\n", from, to, (id == nil) ? "" : id, d);
+}
+
+int
+registerjacc(int sock, char *serv, char *user, char *pass)
+{
+ return fprint(sock, "<iq type=\"set\" id=\"req\" to=\"%s\">\n"
+ "<query xmlns=\"jabber:iq:register\">\n"
+ "<username>%s</username>\n"
+ "<password>%s</password>\n"
+ "</query>\n"
+ "</iq>\n", serv, user, pass);
+}
+
+int
+vcardgetjacc(int sock, char *from, char *type)
+{
+ return fprint(sock, "<iq %s=\"%s\" type=\"get\" id=\"v1\">\n"
+ "<vCard xmlns=\"vcard-temp\"/>\n"
+ "</iq>\n", type, from);
+}
+
+int
+vcardsetjacc(int sock, char *from, int fd)
+{
+ fprint(sock, "<iq from=\"%s\" type=\"set\" id=\"v2\">\n"
+ "<vCard xmlns=\"vcard-temp\">\n", from);
+ readwrite(sock, fd);
+
+ return fprint(sock, "</vCard>\n"
+ "</iq>\n");
+}
+
+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>9</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
+presencetypejacc(int sock, char *from, char *to, char *type)
+{
+ return fprint(sock, "<presence type=\"%s\" from=\"%s\" to=\"%s\"/>\n",
+ type, from, to);
+}
+
+int
+rosterjacc(int sock)
+{
+ return fprint(sock, "<iq type=\"get\" id=\"auth_2\">\n"
+ "<query xmlns=\"jabber:iq:roster\"/>\n"
+ "</iq>\n");
+}
+
+int
+messagejacc(int sock, char *from, char *to, char *msg, char *type)
+{
+ return fprint(sock, "<message from=\"%s\" to=\"%s\" type=\"%s\">\n"
+ "<body>%s</body>\n"
+ "</message>\n", from, to, type, msg);
+}
+
+int
+addbuddyjacc(int sock, char *jid, char *na, char *group)
+{
+ if(na == nil){
+ na = jid;
+ jid = strchr(na, '@');
+
+ if(jid == nil)
+ return -1;
+ *jid++ = '\0';
+
+ return fprint(sock, "<iq type=\"set\">\n"
+ "<query xmlns=\"jabber:iq:roster\">\n"
+ "<item jid=\"%s@%s\" name=\"%s\"/>\n"
+ "%s%s%s"
+ "</query>\n"
+ "</iq>\n", na, jid, na,
+ (group != nil) ? "<group>" : "",
+ (group != nil) ? group : "",
+ (group != nil) ? "</group>\n" : "");
+ }
+
+ return fprint(sock, "<iq type=\"set\">\n"
+ "<query xmlns=\"jabber:iq:roster\">\n"
+ "<item jid=\"%s\" name=\"%s\"/>\n"
+ "%s%s%s"
+ "</query>\n"
+ "</iq>\n", jid, na,
+ (group != nil) ? "<group>" : "",
+ (group != nil) ? group : "",
+ (group != nil) ? "</group>\n" : "");
+}
+
+int
+delbuddyjacc(int sock, char *jid)
+{
+ return fprint(sock, "<iq type=\"set\">\n"
+ "<query xmlns=\"jabber:iq:roster\">\n"
+ "<item jid=\"%s\" subscription=\"remove\"/>\n"
+ "</query>\n"
+ "</iq>\n", jid);
+}
+
+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);
+}
+
+void
+printrostern(rostern *r, char *w)
+{
+ char *tmstmp;
+
+ tmstmp = mktmstmp('(', ')');
+ while(r != nil){
+ if(w != nil){
+ if(r->status != nil)
+ if(!strcmp(r->status, w))
+ goto got_one;
+ if(r->name != nil)
+ if(!strcmp(r->name, w))
+ goto got_one;
+ if(r->jid != nil)
+ if(!strcmp(r->jid, w))
+ goto got_one;
+ if(r->show != nil)
+ if(!strcmp(r->show, w))
+ goto got_one;
+ if(r->group != nil)
+ if(!strcmp(r->group, w))
+ goto got_one;
+ } else {
+got_one:
+ print("%s%s/%s on %s -> %s/%s\n", tmstmp, r->name, r->jid, r->group, r->show, r->status);
+ }
+
+ r = r->n;
+ }
+
+ return;
+}
+
+void
+usage(void)
+{
+ print("usage: [-dgit] [-r res] [-s tosrv] [net!]server[!port]\n");
+ exits(0);
+}
+
+void admin (int sock, char *id, char *room, char *item)
+{
+ fprint(sock, "<iq id=\"%s\" to=\"%s\" type=\"set\"><query xmlns=\"http://jabber.org/protocol/muc#admin\"><item %s /></query></iq>", id, room, item);
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ char *server, *user, *lbl, *b, *tmstmp, *buf, *toserver, *role, *tmp;
+ int sock, ts, reg, debug, tls;
+ UserPasswd *i;
+ TLSconn conn;
+ jabberc *me;
+
+ tls = 0;
+ b = nil;
+ reg = 0;
+ debug = 0;
+ toserver = nil;
+
+ ARGBEGIN {
+ case 't':
+ tls = 1;
+ break;
+ case 'r':
+ b = EARGF(usage());
+ break;
+ case 'g':
+ reg = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'i':
+ doignore = 1;
+ break;
+ case 's':
+ toserver = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc < 1)
+ usage();
+ server = strdup(argv[0]);
+
+ lbl = getwindowlbl();
+ user = reallocj(nil, strlen(server) + 9, 2);
+ snprint(user, strlen(server) + 8, "jacc - %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->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");
+ me->jid = printjid(me->name, me->serv, me->reso);
+ me->debug = debug;
+ me->reg = reg;
+ me->last = time(0);
+
+ free(server);
+
+ ts = getpid();
+
+#ifdef PLAN9PORT
+ switch(fork()) {
+#endif
+#ifndef PLAN9PORT
+ switch(rfork(RFPROC|RFFDG|RFMEM)) {
+#endif
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ if(recvjacc(sock, me, i->passwd) < 0)
+ perror("recvjacc");
+
+ if(lbl != nil){
+ setwindowlbl(lbl);
+ lbl = nil;
+ free(lbl);
+ }
+ killproc(ts);
+ exits(0);
+ default:
+ user = reallocj(nil, 1025, 2);
+ buf = nil;
+ while(sock > 0 && user != nil){
+ ts = -1;
+ memset(user, 0, 1025);
+
+ while(read(0, &user[++ts], 1) && ts < 1024 && sock > 0)
+ if(user[ts] == '\n')
+ break;
+ user[ts] = '\0';
+ me->last = time(0);
+
+ tmstmp = mktmstmp('(', ')');
+ if(user[0] != '/'){
+ if(buf != nil){
+ b = filterhin(user, 0);
+ messagejacc(sock, me->jid, buf, b, "chat");
+ print("%s\n", tmstmp);
+ free(b);
+ }
+ free(tmstmp);
+ continue;
+ }
+ if (user[1] == 'x'){
+ b = getarg(user, 1, 0);
+ if(b != nil){
+ if (strcmp(b, "join") == 0){
+ free(b);
+
+ server = getarg(user, 2, 0);
+
+ if(server != nil){
+ b = getarg(user, 3, 0);
+ if(b == nil)
+ b = strdup(me->name);
+
+ fprint(sock, "<presence to=\"%s/%s\"/>", server, b);
+ free (server);
+ free(b);
+ }
+ }
+ else
+ if (strcmp(b, "leave") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil) {
+ fprint(sock,
+ "<presence to='%s' type='unavailable'/>", server);
+ free (server);
+ }
+
+ }
+ else
+ if (strcmp(b, "say") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ b = getarg(user, 3, 2);
+ if(b != nil){
+ messagejacc(sock,
+ me->jid, server, b, "groupchat");
+ free(b);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "priv") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = server;
+ server = smprint("%s/%s", server, role);
+ free(tmp);
+
+ messagejacc(sock,
+ me->jid, server, b, "chat");
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "role") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = b;
+ b = smprint("nick='%s' role='%s'", b, role);
+ free(tmp);
+
+ admin(sock, role, server, b);
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "affil") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = b;
+ b = smprint("jid='%s' affiliation='%s'", b, role);
+ free(tmp);
+
+ admin(sock, role, server, b);
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ free(b);
+ }
+ }
+ else
+ switch(user[1]){
+ case 'h':
+ case 'H':
+ print("%sHelp for jacc:\n", tmstmp);
+ print("%s /a [+|-|*]jid - authenticate jid\n", tmstmp);
+ print("%s /b - turn debugging on or off\n", tmstmp);
+ print("%s /c file - set vcard on server\n", tmstmp);
+ print("%s /d jid [feat] - do a discovery request\n", tmstmp);
+ print("%s /e jid - get time from jid\n", tmstmp);
+ print("%s /g jid - get agents information from jid\n", tmstmp);
+ print("%s /h - print out this help\n", tmstmp);
+ print("%s /i jid - get version of jid\n", tmstmp);
+ print("%s /l [status|jid|user] - list the roster\n", tmstmp);
+ print("%s /m jid - send a message to jid\n", tmstmp);
+ print("%s /p [show] [status] - set status and show\n", tmstmp);
+ print("%s /q - quit jacc\n", tmstmp);
+ print("%s /s [jid] - set active jid\n", tmstmp);
+ print("%s /t jid - get idle time of jid\n",tmstmp);
+ print("%s /u [+|-]jid [alias] - manage roster\n", tmstmp);
+ print("%s /v [jid] - get vcard from jid\n", tmstmp);
+
+ print("%s /x command - operate with groupchat\n", tmstmp);
+ print("%s commands:\n", tmstmp);
+ print("%s groupchat - leave groupchat\n", tmstmp);
+ print("%s join groupchat [nick] - join to the groupchat\n", tmstmp);
+// print("%s names groupchat - occupants' list\n", tmstmp);
+ print("%s say groupchat - send a message to groupchat\n", tmstmp);
+ print("%s priv groupchat nick - send a private message to occupant\n", tmstmp);
+ print("%s leave groupchat - leave groupchat\n", tmstmp);
+ print("%s affil groupchat affilation jid - set affilation\n", tmstmp);
+ print("%s role groupchat role nick - set role\n", tmstmp);
+ break;
+
+ case 'q':
+ case 'Q':
+ fprint(sock, "<presence from=\"%s\" type=\"unavailable\"/>",
+ me->jid);
+ fprint(sock, "</stream:stream>");
+ free(user);
+ user = nil;
+ break;
+ case 's':
+ case 'S':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ print("%s%s\n", tmstmp, (buf != nil) ? buf : "<nil>");
+ break;
+ }
+
+ buf = setchan(buf, namerostern(me->rost, nil, server));
+ free(server);
+ break;
+ case 'l':
+ case 'L':
+ server = getarg(user, 1, 0);
+
+ printrostern(me->rost, server);
+
+ if(server != nil)
+ free(server);
+ break;
+ case 'm':
+ case 'M':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+
+ b = getarg(user, 2, 2);
+ if(b != nil){
+ messagejacc(sock, me->jid, namerostern(me->rost, nil, server), b, "normal");
+ free(b);
+ }
+
+ free(server);
+ }
+ break;
+ case 'p':
+ case 'P':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ print("%s%s\n", tmstmp, me->stat);
+ break;
+ }
+
+ b = getarg(user, 2, 2);
+ if(b != nil){
+ presencejacc(sock, b, server, nil, nil);
+ free(me->stat);
+ me->stat = strdup(b);
+ } else
+ presencejacc(sock, nil, server, nil, nil);
+ free(me->show);
+ me->show = strdup(server);
+ statusrostern(me->rost, me->jid, me->jid, server, b);
+ free(server);
+ break;
+ case 'c':
+ case 'C':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ ts = open(server, OREAD);
+ if(ts >= 0){
+ vcardsetjacc(sock, me->jid, ts);
+ close(ts);
+ }
+ free(server);
+ }
+ break;
+ case 'v':
+ case 'V':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ vcardgetjacc(sock, me->jid, "from");
+ break;
+ }
+
+ vcardgetjacc(sock, namerostern(me->rost, nil, server), "to");
+ print("Vcard of: %s\n", namerostern(me->rost, nil, server));
+ free(server);
+ break;
+ case 'u':
+ case 'U':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ if(server[0] == '-')
+ delbuddyjacc(sock, namerostern(me->rost, server + 1, server + 1));
+ else {
+ b = getarg(user, 2, 0);
+ if(server[0] == '+')
+ addbuddyjacc(sock, server + 1, b, nil);
+ else
+ addbuddyjacc(sock, server, b, nil);
+ }
+ free(server);
+ }
+ break;
+ case 'a':
+ case 'A':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ switch(server[0]){
+ case '+':
+ presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "subscribed");
+ break;
+ case '-':
+ presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "unsubscribe");
+ break;
+ case '*':
+ presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server + 1), "subscribe");
+ break;
+ default:
+ presencetypejacc(sock, me->jid, namerostern(me->rost, nil, server), "subscribed");
+ break;
+ }
+ free(server);
+ }
+ break;
+ case 'd':
+ case 'D':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ b = getarg(user, 2, 2);
+ if(b == nil)
+ b = strdup("info");
+
+ free(tmstmp);
+ tmstmp = reallocj(nil, 35 + strlen(b), 2);
+ sprint(tmstmp, "http://jabber.org/protocol/disco#%s", b);
+
+ xmlnsjacc(sock, server, tmstmp, "disco0");
+ free(b);
+ free(server);
+ }
+ break;
+ case 'b':
+ case 'B':
+ if(me->debug == 0)
+ me->debug = 1;
+ else
+ me->debug = 0;
+ print("%sDebug: %c\n", tmstmp, me->debug);
+ break;
+ case 't':
+ case 'T':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:last", "last0");
+ free(server);
+ }
+ break;
+ case 'i':
+ case 'I':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:version", "version0");
+ free(server);
+ }
+ break;
+ case 'e':
+ case 'E':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:time", "time0");
+ free(server);
+ }
+ break;
+ case 'g':
+ case 'G':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me->rost, nil, server), "jabber:iq:agents", "agents0");
+ free(server);
+ }
+ break;
+
+ default:
+ break;
+ }
+ free(tmstmp);
+ }
+
+ wait();
+ if(lbl != nil){
+ setwindowlbl(lbl);
+ lbl = nil;
+ free(lbl);
+ }
+ break;
+ }
+
+ freejabberc(me);
+ exits(0);
+ return 0;
+}
diff --git a/jacc.c b/jacc.c
new file mode 100644
index 0000000..f0a29ea
--- /dev/null
+++ b/jacc.c
@@ -0,0 +1,820 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=utf8">
+<title>/n/sources/contrib/stassats/jacc.c - Plan 9 from Bell Labs</title>
+<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
+<!-- EDIT sources.tr INSTEAD. -->
+</meta>
+</head>
+<body>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
+<span style="font-size: 10pt"><a href="http://plan9.bell-labs.com/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /n/sources/contrib/stassats/jacc.c</span></p>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<center><font size=-1>
+Copyright © 2009 Alcatel-Lucent.<br />
+Distributed under the
+<a href="http://plan9.bell-labs.com/plan9/license.html">Lucent Public License version 1.02</a>.
+<br />
+<a href="http://plan9.bell-labs.com/plan9/download.html">Download the Plan 9 distribution.</a>
+</font>
+</center>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<table width="100%" cellspacing=0 border=0><tr><td align="center">
+<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
+<pre>
+<!-- END HEADER -->
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#include &lt;u.h&gt;
+#include &lt;libc.h&gt;
+#include &lt;auth.h&gt;
+#include &lt;mp.h&gt;
+#include &lt;libsec.h&gt;
+#include "xmlpull.h"
+#include "jacc.h"
+#include "dat.h"
+#include "roster.h"
+#include "recv.h"
+
+#define NAME "jacc - Jabber Client for Plan9"
+#define VERSION "3rd ed"
+#define OS "Plan 9 4th ed"
+
+extern int doignore;
+
+int
+xmljacc(int sock)
+{
+ return fprint(sock, "&lt;?xml version=\"1.0\"?&gt;\n");
+}
+
+int
+loginjacc(int sock, char *serv)
+{
+ return fprint(sock, "&lt;stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\""
+ " xmlns=\"jabber:client\" to=\"%s\"&gt;\n", serv);
+}
+
+int
+userjacc(int sock, char *user, char *pass, char *res)
+{
+ return fprint(sock, "&lt;iq type=\"set\" id=\"auth_1\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:auth\"&gt;\n"
+ "&lt;username&gt;%s&lt;/username&gt;\n"
+ "&lt;password&gt;%s&lt;/password&gt;\n"
+ "&lt;resource&gt;%s&lt;/resource&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", user, pass, res);
+}
+
+int
+versionjacc(int sock, char *from, char *to, char *id)
+{
+ return fprint(sock, "&lt;iq from=\"%s\" type=\"result\" id=\"%s\" to=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:version\"&gt;\n"
+ "&lt;name&gt;" NAME "&lt;/name&gt;\n"
+ "&lt;version&gt;" VERSION "&lt;/version&gt;\n"
+ "&lt;os&gt;" OS "&lt;/os&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", from, (id == nil) ? "" : id, to);
+}
+
+int
+featuresjacc(int sock, char *from, char *to, char *id)
+{
+ return fprint(sock, "&lt;iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"http://jabber.org/protocol/disco#info\"&gt;\n"
+ "&lt;identity category=\"client\" type=\"pc\"/&gt;\n"
+ "&lt;feature var=\"jabber:iq:time\"/&gt;\n"
+ "&lt;feature var=\"jabber:iq:version\"/&gt;\n"
+ "&lt;feature var=\"http://jabber.org/protocol/muc\"/&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", from, to, (id == nil) ? "" : id);
+}
+
+int
+timejacc(int sock, char *from, char *to, char *id)
+{
+ Tm *lo, *gm;
+
+ lo = localtime(time(0));
+ gm = gmtime(time(0));
+
+ return fprint(sock, "&lt;iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:time\"&gt;\n"
+ "&lt;utc&gt;%.4d%.2d%.2dT%.2d:%.2d:%.2d&lt;/utc&gt;\n"
+ "&lt;display&gt;%s %s %.2d %.2d:%.2d:%.2d %.4d&lt;/display&gt;\n"
+ "&lt;tz&gt;%s&lt;/tz&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", from, to, (id == nil) ? "" : id, gm-&gt;year + 1900,
+ gm-&gt;mon + 1, gm-&gt;mday, gm-&gt;hour, gm-&gt;min,
+ gm-&gt;sec, getday(lo-&gt;wday), getmonth(lo-&gt;mon),
+ lo-&gt;mday, lo-&gt;hour, lo-&gt;min, lo-&gt;sec,
+ lo-&gt;year + 1900, lo-&gt;zone);
+}
+
+int
+lastjacc(int sock, char *from, char *to, char *id, int d)
+{
+ return fprint(sock, "&lt;iq from=\"%s\" type=\"result\" to=\"%s\" id=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:last\" seconds=\"%d\"/&gt;\n"
+ "&lt;/iq&gt;\n", from, to, (id == nil) ? "" : id, d);
+}
+
+int
+registerjacc(int sock, char *serv, char *user, char *pass)
+{
+ return fprint(sock, "&lt;iq type=\"set\" id=\"req\" to=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:register\"&gt;\n"
+ "&lt;username&gt;%s&lt;/username&gt;\n"
+ "&lt;password&gt;%s&lt;/password&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", serv, user, pass);
+}
+
+int
+vcardgetjacc(int sock, char *from, char *type)
+{
+ return fprint(sock, "&lt;iq %s=\"%s\" type=\"get\" id=\"v1\"&gt;\n"
+ "&lt;vCard xmlns=\"vcard-temp\"/&gt;\n"
+ "&lt;/iq&gt;\n", type, from);
+}
+
+int
+vcardsetjacc(int sock, char *from, int fd)
+{
+ fprint(sock, "&lt;iq from=\"%s\" type=\"set\" id=\"v2\"&gt;\n"
+ "&lt;vCard xmlns=\"vcard-temp\"&gt;\n", from);
+ readwrite(sock, fd);
+
+ return fprint(sock, "&lt;/vCard&gt;\n"
+ "&lt;/iq&gt;\n");
+}
+
+int
+presencejacc(int sock, char *stat, char *show, char *from, char *to)
+{
+ return fprint(sock, "&lt;presence%s%s%s%s%s%s&gt;\n"
+ "&lt;show&gt;%s&lt;/show&gt;\n"
+ "&lt;status&gt;%s&lt;/status&gt;\n"
+ "&lt;priority&gt;9&lt;/priority&gt;\n"
+ "&lt;/presence&gt;\n", (from != nil) ? " from=\"" : "",
+ (from != nil) ? from : "",
+ (from != nil) ? "\"" : "",
+ (to != nil) ? " to=\"" : "",
+ (to != nil) ? to : "",
+ (to != nil) ? "\"" : "",
+ (show != nil) ? show : "",
+ (stat != nil) ? stat : "");
+}
+
+int
+presencetypejacc(int sock, char *from, char *to, char *type)
+{
+ return fprint(sock, "&lt;presence type=\"%s\" from=\"%s\" to=\"%s\"/&gt;\n",
+ type, from, to);
+}
+
+int
+rosterjacc(int sock)
+{
+ return fprint(sock, "&lt;iq type=\"get\" id=\"auth_2\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:roster\"/&gt;\n"
+ "&lt;/iq&gt;\n");
+}
+
+int
+messagejacc(int sock, char *from, char *to, char *msg, char *type)
+{
+ return fprint(sock, "&lt;message from=\"%s\" to=\"%s\" type=\"%s\"&gt;\n"
+ "&lt;body&gt;%s&lt;/body&gt;\n"
+ "&lt;/message&gt;\n", from, to, type, msg);
+}
+
+int
+addbuddyjacc(int sock, char *jid, char *na, char *group)
+{
+ if(na == nil){
+ na = jid;
+ jid = strchr(na, '@');
+
+ if(jid == nil)
+ return -1;
+ *jid++ = '\0';
+
+ return fprint(sock, "&lt;iq type=\"set\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:roster\"&gt;\n"
+ "&lt;item jid=\"%s@%s\" name=\"%s\"/&gt;\n"
+ "%s%s%s"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", na, jid, na,
+ (group != nil) ? "&lt;group&gt;" : "",
+ (group != nil) ? group : "",
+ (group != nil) ? "&lt;/group&gt;\n" : "");
+ }
+
+ return fprint(sock, "&lt;iq type=\"set\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:roster\"&gt;\n"
+ "&lt;item jid=\"%s\" name=\"%s\"/&gt;\n"
+ "%s%s%s"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", jid, na,
+ (group != nil) ? "&lt;group&gt;" : "",
+ (group != nil) ? group : "",
+ (group != nil) ? "&lt;/group&gt;\n" : "");
+}
+
+int
+delbuddyjacc(int sock, char *jid)
+{
+ return fprint(sock, "&lt;iq type=\"set\"&gt;\n"
+ "&lt;query xmlns=\"jabber:iq:roster\"&gt;\n"
+ "&lt;item jid=\"%s\" subscription=\"remove\"/&gt;\n"
+ "&lt;/query&gt;\n"
+ "&lt;/iq&gt;\n", jid);
+}
+
+int
+xmlnsjacc(int sock, char *who, char *t, char *id)
+{
+ return fprint(sock, "&lt;iq type=\"get\" to=\"%s\" id=\"%s\"&gt;\n"
+ "&lt;query xmlns=\"%s\"/&gt;\n"
+ "&lt;/iq&gt;\n", who, id, t);
+}
+
+void
+printrostern(rostern *r, char *w)
+{
+ char *tmstmp;
+
+ tmstmp = mktmstmp('(', ')');
+ while(r != nil){
+ if(w != nil){
+ if(r-&gt;status != nil)
+ if(!strcmp(r-&gt;status, w))
+ goto got_one;
+ if(r-&gt;name != nil)
+ if(!strcmp(r-&gt;name, w))
+ goto got_one;
+ if(r-&gt;jid != nil)
+ if(!strcmp(r-&gt;jid, w))
+ goto got_one;
+ if(r-&gt;show != nil)
+ if(!strcmp(r-&gt;show, w))
+ goto got_one;
+ if(r-&gt;group != nil)
+ if(!strcmp(r-&gt;group, w))
+ goto got_one;
+ } else {
+got_one:
+ print("%s%s/%s on %s -&gt; %s/%s\n", tmstmp, r-&gt;name, r-&gt;jid, r-&gt;group, r-&gt;show, r-&gt;status);
+ }
+
+ r = r-&gt;n;
+ }
+
+ return;
+}
+
+void
+usage(void)
+{
+ print("usage: [-dgit] [-r res] [-s tosrv] [net!]server[!port]\n");
+ exits(0);
+}
+
+void admin (int sock, char *id, char *room, char *item)
+{
+ fprint(sock, "&lt;iq id=\"%s\" to=\"%s\" type=\"set\"&gt;&lt;query xmlns=\"http://jabber.org/protocol/muc#admin\"&gt;&lt;item %s /&gt;&lt;/query&gt;&lt;/iq&gt;", id, room, item);
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+ char *server, *user, *lbl, *b, *tmstmp, *buf, *toserver, *role, *tmp;
+ int sock, ts, reg, debug, tls;
+ UserPasswd *i;
+ TLSconn conn;
+ jabberc *me;
+
+ tls = 0;
+ b = nil;
+ reg = 0;
+ debug = 0;
+ toserver = nil;
+
+ ARGBEGIN {
+ case 't':
+ tls = 1;
+ break;
+ case 'r':
+ b = EARGF(usage());
+ break;
+ case 'g':
+ reg = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'i':
+ doignore = 1;
+ break;
+ case 's':
+ toserver = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc &lt; 1)
+ usage();
+ server = strdup(argv[0]);
+
+ lbl = getwindowlbl();
+ user = reallocj(nil, strlen(server) + 9, 2);
+ snprint(user, strlen(server) + 8, "jacc - %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 &lt; 0)
+ sysfatal("dial: %r");
+
+ if(tls){
+ ts = tlsClient(sock, &amp;conn);
+ if(ts &lt; 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-&gt;show = strdup("Online");
+ me-&gt;stat = strdup("Online");
+ me-&gt;name = strdup(i-&gt;user);
+ me-&gt;serv = strdup(toserver);
+
+ if(b != nil)
+ me-&gt;reso = strdup(b);
+ else
+ me-&gt;reso = strdup("Plan9");
+ me-&gt;jid = printjid(me-&gt;name, me-&gt;serv, me-&gt;reso);
+ me-&gt;debug = debug;
+ me-&gt;reg = reg;
+ me-&gt;last = time(0);
+
+ free(server);
+
+ ts = getpid();
+
+#ifdef PLAN9PORT
+ switch(fork()) {
+#endif
+#ifndef PLAN9PORT
+ switch(rfork(RFPROC|RFFDG|RFMEM)) {
+#endif
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ if(recvjacc(sock, me, i-&gt;passwd) &lt; 0)
+ perror("recvjacc");
+
+ if(lbl != nil){
+ setwindowlbl(lbl);
+ lbl = nil;
+ free(lbl);
+ }
+ killproc(ts);
+ exits(0);
+ default:
+ user = reallocj(nil, 1025, 2);
+ buf = nil;
+ while(sock &gt; 0 &amp;&amp; user != nil){
+ ts = -1;
+ memset(user, 0, 1025);
+
+ while(read(0, &amp;user[++ts], 1) &amp;&amp; ts &lt; 1024 &amp;&amp; sock &gt; 0)
+ if(user[ts] == '\n')
+ break;
+ user[ts] = '\0';
+ me-&gt;last = time(0);
+
+ tmstmp = mktmstmp('(', ')');
+ if(user[0] != '/'){
+ if(buf != nil){
+ b = filterhin(user, 0);
+ messagejacc(sock, me-&gt;jid, buf, b, "chat");
+ print("%s\n", tmstmp);
+ free(b);
+ }
+ free(tmstmp);
+ continue;
+ }
+ if (user[1] == 'x'){
+ b = getarg(user, 1, 0);
+ if(b != nil){
+ if (strcmp(b, "join") == 0){
+ free(b);
+
+ server = getarg(user, 2, 0);
+
+ if(server != nil){
+ b = getarg(user, 3, 0);
+ if(b == nil)
+ b = strdup(me-&gt;name);
+
+ fprint(sock, "&lt;presence to=\"%s/%s\"/&gt;", server, b);
+ free (server);
+ free(b);
+ }
+ }
+ else
+ if (strcmp(b, "leave") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil) {
+ fprint(sock,
+ "&lt;presence to='%s' type='unavailable'/&gt;", server);
+ free (server);
+ }
+
+ }
+ else
+ if (strcmp(b, "say") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ b = getarg(user, 3, 2);
+ if(b != nil){
+ messagejacc(sock,
+ me-&gt;jid, server, b, "groupchat");
+ free(b);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "priv") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = server;
+ server = smprint("%s/%s", server, role);
+ free(tmp);
+
+ messagejacc(sock,
+ me-&gt;jid, server, b, "chat");
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "role") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = b;
+ b = smprint("nick='%s' role='%s'", b, role);
+ free(tmp);
+
+ admin(sock, role, server, b);
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ if (strcmp(b, "affil") == 0){
+ free(b);
+ server = getarg(user, 2, 0);
+ if(server != nil){
+ role = getarg(user, 3, 0);
+ if(role != nil){
+ b = getarg(user, 4, 2);
+ if(b != nil){
+ tmp = b;
+ b = smprint("jid='%s' affiliation='%s'", b, role);
+ free(tmp);
+
+ admin(sock, role, server, b);
+ free(b);
+ }
+ free(role);
+ }
+ free(server);
+ }
+ }
+ else
+ free(b);
+ }
+ }
+ else
+ switch(user[1]){
+ case 'h':
+ case 'H':
+ print("%sHelp for jacc:\n", tmstmp);
+ print("%s /a [+|-|*]jid - authenticate jid\n", tmstmp);
+ print("%s /b - turn debugging on or off\n", tmstmp);
+ print("%s /c file - set vcard on server\n", tmstmp);
+ print("%s /d jid [feat] - do a discovery request\n", tmstmp);
+ print("%s /e jid - get time from jid\n", tmstmp);
+ print("%s /g jid - get agents information from jid\n", tmstmp);
+ print("%s /h - print out this help\n", tmstmp);
+ print("%s /i jid - get version of jid\n", tmstmp);
+ print("%s /l [status|jid|user] - list the roster\n", tmstmp);
+ print("%s /m jid - send a message to jid\n", tmstmp);
+ print("%s /p [show] [status] - set status and show\n", tmstmp);
+ print("%s /q - quit jacc\n", tmstmp);
+ print("%s /s [jid] - set active jid\n", tmstmp);
+ print("%s /t jid - get idle time of jid\n",tmstmp);
+ print("%s /u [+|-]jid [alias] - manage roster\n", tmstmp);
+ print("%s /v [jid] - get vcard from jid\n", tmstmp);
+
+ print("%s /x command - operate with groupchat\n", tmstmp);
+ print("%s commands:\n", tmstmp);
+ print("%s groupchat - leave groupchat\n", tmstmp);
+ print("%s join groupchat [nick] - join to the groupchat\n", tmstmp);
+// print("%s names groupchat - occupants' list\n", tmstmp);
+ print("%s say groupchat - send a message to groupchat\n", tmstmp);
+ print("%s priv groupchat nick - send a private message to occupant\n", tmstmp);
+ print("%s leave groupchat - leave groupchat\n", tmstmp);
+ print("%s affil groupchat affilation jid - set affilation\n", tmstmp);
+ print("%s role groupchat role nick - set role\n", tmstmp);
+ break;
+
+ case 'q':
+ case 'Q':
+ fprint(sock, "&lt;presence from=\"%s\" type=\"unavailable\"/&gt;",
+ me-&gt;jid);
+ fprint(sock, "&lt;/stream:stream&gt;");
+ free(user);
+ user = nil;
+ break;
+ case 's':
+ case 'S':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ print("%s%s\n", tmstmp, (buf != nil) ? buf : "&lt;nil&gt;");
+ break;
+ }
+
+ buf = setchan(buf, namerostern(me-&gt;rost, nil, server));
+ free(server);
+ break;
+ case 'l':
+ case 'L':
+ server = getarg(user, 1, 0);
+
+ printrostern(me-&gt;rost, server);
+
+ if(server != nil)
+ free(server);
+ break;
+ case 'm':
+ case 'M':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+
+ b = getarg(user, 2, 2);
+ if(b != nil){
+ messagejacc(sock, me-&gt;jid, namerostern(me-&gt;rost, nil, server), b, "normal");
+ free(b);
+ }
+
+ free(server);
+ }
+ break;
+ case 'p':
+ case 'P':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ print("%s%s\n", tmstmp, me-&gt;stat);
+ break;
+ }
+
+ b = getarg(user, 2, 2);
+ if(b != nil){
+ presencejacc(sock, b, server, nil, nil);
+ free(me-&gt;stat);
+ me-&gt;stat = strdup(b);
+ } else
+ presencejacc(sock, nil, server, nil, nil);
+ free(me-&gt;show);
+ me-&gt;show = strdup(server);
+ statusrostern(me-&gt;rost, me-&gt;jid, me-&gt;jid, server, b);
+ free(server);
+ break;
+ case 'c':
+ case 'C':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ ts = open(server, OREAD);
+ if(ts &gt;= 0){
+ vcardsetjacc(sock, me-&gt;jid, ts);
+ close(ts);
+ }
+ free(server);
+ }
+ break;
+ case 'v':
+ case 'V':
+ server = getarg(user, 1, 0);
+ if(server == nil){
+ vcardgetjacc(sock, me-&gt;jid, "from");
+ break;
+ }
+
+ vcardgetjacc(sock, namerostern(me-&gt;rost, nil, server), "to");
+ print("Vcard of: %s\n", namerostern(me-&gt;rost, nil, server));
+ free(server);
+ break;
+ case 'u':
+ case 'U':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ if(server[0] == '-')
+ delbuddyjacc(sock, namerostern(me-&gt;rost, server + 1, server + 1));
+ else {
+ b = getarg(user, 2, 0);
+ if(server[0] == '+')
+ addbuddyjacc(sock, server + 1, b, nil);
+ else
+ addbuddyjacc(sock, server, b, nil);
+ }
+ free(server);
+ }
+ break;
+ case 'a':
+ case 'A':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ switch(server[0]){
+ case '+':
+ presencetypejacc(sock, me-&gt;jid, namerostern(me-&gt;rost, nil, server + 1), "subscribed");
+ break;
+ case '-':
+ presencetypejacc(sock, me-&gt;jid, namerostern(me-&gt;rost, nil, server + 1), "unsubscribe");
+ break;
+ case '*':
+ presencetypejacc(sock, me-&gt;jid, namerostern(me-&gt;rost, nil, server + 1), "subscribe");
+ break;
+ default:
+ presencetypejacc(sock, me-&gt;jid, namerostern(me-&gt;rost, nil, server), "subscribed");
+ break;
+ }
+ free(server);
+ }
+ break;
+ case 'd':
+ case 'D':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ b = getarg(user, 2, 2);
+ if(b == nil)
+ b = strdup("info");
+
+ free(tmstmp);
+ tmstmp = reallocj(nil, 35 + strlen(b), 2);
+ sprint(tmstmp, "http://jabber.org/protocol/disco#%s", b);
+
+ xmlnsjacc(sock, server, tmstmp, "disco0");
+ free(b);
+ free(server);
+ }
+ break;
+ case 'b':
+ case 'B':
+ if(me-&gt;debug == 0)
+ me-&gt;debug = 1;
+ else
+ me-&gt;debug = 0;
+ print("%sDebug: %c\n", tmstmp, me-&gt;debug);
+ break;
+ case 't':
+ case 'T':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me-&gt;rost, nil, server), "jabber:iq:last", "last0");
+ free(server);
+ }
+ break;
+ case 'i':
+ case 'I':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me-&gt;rost, nil, server), "jabber:iq:version", "version0");
+ free(server);
+ }
+ break;
+ case 'e':
+ case 'E':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me-&gt;rost, nil, server), "jabber:iq:time", "time0");
+ free(server);
+ }
+ break;
+ case 'g':
+ case 'G':
+ server = getarg(user, 1, 0);
+ if(server != nil){
+ xmlnsjacc(sock, namerostern(me-&gt;rost, nil, server), "jabber:iq:agents", "agents0");
+ free(server);
+ }
+ break;
+
+ default:
+ break;
+ }
+ free(tmstmp);
+ }
+
+ wait();
+ if(lbl != nil){
+ setwindowlbl(lbl);
+ lbl = nil;
+ free(lbl);
+ }
+ break;
+ }
+
+ freejabberc(me);
+ exits(0);
+ return 0;
+}
+<!-- BEGIN TAIL -->
+</pre>
+</td></tr></table>
+</td></tr></table>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
+<span style="font-size: 10pt">(This is a user-contributed directory and <br> should not be interpreted as statement by Lucent.)</span></p>
+<p style="margin-top: 0; margin-bottom: 0.50in"></p>
+<p style="margin-top: 0; margin-bottom: 0.33in"></p>
+<center><table border="0"><tr>
+<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
+</a></td>
+<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
+</a></td>
+<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
+</td>
+</tr></table></center>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<center>
+<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
+</center>
+<p style="margin-top: 0; margin-bottom: 0.17in"></p>
+<center><font size=-1>
+<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
+<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
+<span style="font-size: 10pt">All Rights Reserved.</span>
+<br />
+<span style="font-size: 10pt">Comments to</span>
+<span style="font-size: 10pt"><a href="mailto:webmaster@plan9.bell-labs.com">webmaster@plan9.bell-labs.com</a>.</span>
+</font></center>
+</body>
+</html>
+
diff --git a/jacc.tar b/jacc.tar
new file mode 100644
index 0000000..a037c8d
--- /dev/null
+++ b/jacc.tar
Binary files differ