/* * Copy me if you can. * by 20h */ #include #include #include #include #include #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, "\n"); } int loginjacc(int sock, char *serv) { return fprint(sock, "\n", serv); } int userjacc(int sock, char *user, char *pass, char *res) { return fprint(sock, "\n" "\n" "%s\n" "%s\n" "%s\n" "\n" "\n", user, pass, res); } int versionjacc(int sock, char *from, char *to, char *id) { return fprint(sock, "\n" "\n" "" NAME "\n" "" VERSION "\n" "" OS "\n" "\n" "\n", from, (id == nil) ? "" : id, to); } int featuresjacc(int sock, char *from, char *to, char *id) { return fprint(sock, "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\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, "\n" "\n" "%.4d%.2d%.2dT%.2d:%.2d:%.2d\n" "%s %s %.2d %.2d:%.2d:%.2d %.4d\n" "%s\n" "\n" "\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, "\n" "\n" "\n", from, to, (id == nil) ? "" : id, d); } int registerjacc(int sock, char *serv, char *user, char *pass) { return fprint(sock, "\n" "\n" "%s\n" "%s\n" "\n" "\n", serv, user, pass); } int vcardgetjacc(int sock, char *from, char *type) { return fprint(sock, "\n" "\n" "\n", type, from); } int vcardsetjacc(int sock, char *from, int fd) { fprint(sock, "\n" "\n", from); readwrite(sock, fd); return fprint(sock, "\n" "\n"); } int presencejacc(int sock, char *stat, char *show, char *from, char *to) { return fprint(sock, "\n" "%s\n" "%s\n" "9\n" "\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, "\n", type, from, to); } int rosterjacc(int sock) { return fprint(sock, "\n" "\n" "\n"); } int messagejacc(int sock, char *from, char *to, char *msg, char *type) { return fprint(sock, "\n" "%s\n" "\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, "\n" "\n" "\n" "%s%s%s" "\n" "\n", na, jid, na, (group != nil) ? "" : "", (group != nil) ? group : "", (group != nil) ? "\n" : ""); } return fprint(sock, "\n" "\n" "\n" "%s%s%s" "\n" "\n", jid, na, (group != nil) ? "" : "", (group != nil) ? group : "", (group != nil) ? "\n" : ""); } int delbuddyjacc(int sock, char *jid) { return fprint(sock, "\n" "\n" "\n" "\n" "\n", jid); } int xmlnsjacc(int sock, char *who, char *t, char *id) { return fprint(sock, "\n" "\n" "\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, "", 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, "", server, b); free (server); free(b); } } else if (strcmp(b, "leave") == 0){ free(b); server = getarg(user, 2, 0); if(server != nil) { fprint(sock, "", 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, "", me->jid); fprint(sock, ""); 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 : ""); 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; }