ref: 81dfa6bbd4d005a33a1c0b0a64cd8d548f196175
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;
}