ref: 7b3151f0a13823fccc39b2609155ffd1e5fd806f
dir: /rost.c/
#include <u.h> #include <libc.h> #include "xml.h" #include "xmpp.h" enum { Snone = 0, Sto, Sfrom, Sboth, }; char *subscr2str[] = { [Snone] "none", [Sto] "to", [Sfrom] "from", [Sboth] "both", }; char *subscr2fmt[] = { [Snone] "[ ]", [Sto] "[← ]", [Sfrom] "[ →]", [Sboth] "[←→]", }; static char **asked; static int numasked, rostwidth; int rostupdate(Xelem *x, int fd) { Xattr *n, *s, *j; Target *t; int i, width; if(fprint(fd, "<presence/>") < 0) return -1; for(x = x->ch->ch; x != nil; x = x->next){ n = xmlgetattr(x->a, "name"); s = xmlgetattr(x->a, "subscription"); j = xmlgetattr(x->a, "jid"); if(j == nil || s == nil) continue; if(n == nil) n = j; for(i = 0, t = nil; i < numtargets; i++, t = nil){ t = targets[i]; if(t->type == Erost && strcmp(t->jid, j->v) == 0) break; } if(t == nil){ t = addtarget(Erost, n->v); t->jid = strdup(j->v); }else{ if(strcmp(s->v, "remove") == 0){ print("%t removed from roster\n", t); rmtarget(t); continue; } free(t->name); t->name = strdup(n->v); } if((width = utflen(t->name)) > rostwidth) rostwidth = width; for(i = 0; i < nelem(subscr2str); i++){ if(strcmp(s->v, subscr2str[i]) == 0){ t->rost.subscr = i; break; } } } return 0; } int rostsubscr(char *from, char *type, int fd) { Target *t; int i; if(strcmp(type, "subscribe") == 0){ for(i = 0; i < numtargets; i++){ t = targets[i]; if(t->type == Erost && (t->rost.flags & Fasked) && strncmp(t->jid, from, strlen(t->jid)) == 0){ fprint(fd, "<presence to='%Ӽ' type='subscribed'/>", from); return 1; } } for(i = 0; i < numasked; i++) if(strcmp(asked[i], from) == 0) return 1; print("%s asks for a subscription\n", from); numasked++; asked = realloc(asked, numasked*sizeof(asked[0])); asked[numasked-1] = strdup(from); return 1; }else if(strcmp(type, "subscribed") == 0){ for(i = 0; i < numtargets; i++){ t = targets[i]; if(t->type == Erost && strncmp(t->jid, from, strlen(t->jid)) == 0){ t->rost.flags |= Fasked; print("%s has approved subscription\n", from); fprint(fd, "<presence to='%Ӽ' type='subscribe'/>", from); /* ack */ return 1; } } } return 0; } void rostpresence(Xelem *x, Target *t) { Xelem *show; Xattr *type; char *didwhat, *s; int online; didwhat = nil; type = xmlgetattr(x->a, "type"); show = xmlget(x->ch, "show"); online = 1; if(type != nil){ if(strcmp(type->v, "unavailable") == 0) online = 0; else{ if(strcmp(type->v, "unsubscribed") == 0) print("%t cancelled subscription\n", t); else if(strcmp(type->v, "unsubscribe") == 0) print("%t unsubscribed\n", t); return; } } if(!online && (t->rost.flags & Fonline)){ didwhat = "went offline"; t->rost.flags &= ~Fonline; }else if(online && (t->rost.flags & Fonline) == 0){ didwhat = "is online"; t->rost.flags |= Fonline; } if(show == nil) s = ""; else s = show->v; if(t->rost.show != nil && strcmp(s, t->rost.show) == 0) s = nil; else{ free(t->rost.show); t->rost.show = strdup(s); } if(nopresence || didwhat == nil) return; print("[%s] %s %s", strtime(), t->name, didwhat); if(s != nil && s[0] != 0) print(" (%s)", s); print("\n"); } static int cmdrostadd(int fd, char *jid, char *name) { int i; for(i = 0; i < numasked; i++){ if(strncmp(asked[i], jid, strlen(jid)) == 0){ if(fprint(fd, "<presence to='%Ӽ' type='subscribed'/>", asked[i]) < 0) return -1; jid = asked[i]; break; } } if(fprint(fd, "<iq type='set'><query xmlns='jabber:iq:roster'><item jid='%Ӽ'", jid) < 0) return -1; if(name != nil && fprint(fd, " name='%Ӽ'", name) < 0) return -1; if(fprint(fd, "/></query></iq><presence to='%Ӽ' type='subscribe'/>", jid) < 0) return -1; print("asking %s for a subscription\n", jid); if(i < numasked){ free(asked[i]); numasked--; memcpy(&asked[i], &asked[i+1], sizeof(asked[0])*(numasked-i)); } return 0; } static int cmdrostrm(int fd, char *jid) { Target *t; char *a, *b; int i, alen, blen, res; for(i = 0; i < numasked; i++){ if(strncmp(asked[i], jid, strlen(jid)) == 0){ if(fprint(fd, "<presence to='%Ӽ' type='unsubscribed'/>", asked[i]) < 0) return -1; free(asked[i]); numasked--; memcpy(&asked[i], &asked[i+1], sizeof(asked[0])*(numasked-i)); break; } } a = jid; b = strchr(a, '/'); if(b == nil){ blen = 0; alen = strlen(a); }else{ b++; blen = strlen(b); alen = b-1 - a; } res = 0; for(i = 0; i < numtargets; i++){ t = targets[i]; if(t->type == Erost && targmatches(t, a, alen) && (b == nil || strncmp(t->jid, b, blen) == 0)){ res = fprint(fd, "<iq type='set'>" "<query xmlns='jabber:iq:roster'>" "<item jid='%Ӽ' subscription='remove'/>" "</query></iq>", t->jid); if(res > 0) res = fprint(fd, "<presence to='%Ӽ' type='unsubscribe'/>", t->jid); break; } } return res; } static int cmdrostshow(int extra) { int i, num; for(i = num = 0; i < numtargets; i++){ Target *t; t = targets[i]; if(t->type != Erost) continue; if((t->rost.flags & Fonline) == 0 && !extra) continue; print(" %s %*s", subscr2fmt[t->rost.subscr], -rostwidth, t->name); if(t->rost.show != nil && t->rost.show[0] != 0) print(" [%s]", t->rost.show); else if((t->rost.flags & Fonline) == 0) print(" [offline]"); print("\n"); if(extra && strcmp(t->name, t->jid) != 0) print(" %s\n", t->jid); num++; } print("%d user(s) online\n", num); return 0; } int cmdroster(int fd, int argc, char **argv) { int op; op = argv[0][1]; if(op == 0) return cmdrostshow(argv[0][0] == 'R'); else if(op == '+' && argc > 1) return cmdrostadd(fd, argv[1], (argc > 2 ? argv[2] : nil)); else if(op == '-' && argc > 1) return cmdrostrm(fd, argv[1]); return 0; }