#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; introstupdate(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;} introstsubscr(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;} voidrostpresence(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 intcmdrostadd(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 intcmdrostrm(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 intcmdrostshow(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;} intcmdroster(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;}
#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;
}