#include "conference.h"
extern int deliver__flag;
cnu con_user_new(cnr room, jid id)
{
pool p;
cnu user;
char *key;
log_debug(NAME, "[%s] adding user %s to room %s", FZONE, jid_full(jid_fix(id)), jid_full(jid_fix(room->id)));
p = pool_new();
user = pmalloco(p, sizeof(_cnu));
user->p = p;
user->realid = jid_new(user->p, jid_full(jid_fix(id)));
user->room = room;
user->presence = jutil_presnew(JPACKET__AVAILABLE, NULL, NULL);
key = j_strdup(jid_full(user->realid));
g_hash_table_insert(room->remote, key, (void*)user);
add_roster(room, user->realid);
if(is_admin(room, user->realid) && !is_moderator(room, user->realid))
{
log_debug(NAME, "[%s] Adding %s to moderator list", FZONE, jid_full(jid_fix(user->realid)));
add_affiliate(room->admin, user->realid, NULL);
add_role(room->moderator, user);
}
else if(is_member(room, user->realid) && !is_admin(room, user->realid))
{
log_debug(NAME, "[%s] Updating %s in the member list", FZONE, jid_full(user->realid));
add_affiliate(room->member, user->realid, NULL);
add_role(room->participant, user);
}
else if(room->moderated == 1 && room->defaulttype == 1)
{
add_role(room->participant, user);
}
return user;
}
void _con_user_history_send(cnu to, xmlnode node)
{
if(to == NULL || node == NULL)
{
return;
}
xmlnode_put_attrib(node, "to", jid_full(to->realid));
deliver(dpacket_new(node), NULL);
return;
}
void _con_user_nick(gpointer key, gpointer data, gpointer arg)
{
cnu to = (cnu)data;
cnu from = (cnu)arg;
char *old, *status, *reason, *actor;
xmlnode node;
xmlnode result;
xmlnode element;
jid fullid;
if((old = xmlnode_get_attrib(from->nick,"old")) != NULL)
{
if(xmlnode_get_data(from->nick) != NULL)
{
node = jutil_presnew(JPACKET__UNAVAILABLE, jid_full(to->realid), NULL);
}
else
{
node = xmlnode_dup(from->presence);
xmlnode_put_attrib(node, "to", jid_full(to->realid));
}
fullid = jid_new(xmlnode_pool(node), jid_full(from->localid));
jid_set(fullid, old, JID_RESOURCE);
xmlnode_put_attrib(node, "from", jid_full(fullid));
status = xmlnode_get_attrib(from->nick,"status");
log_debug(NAME, "[%s] status = %s", FZONE, status);
reason = xmlnode_get_attrib(from->nick,"reason");
actor = xmlnode_get_attrib(from->nick,"actor");
if(xmlnode_get_data(from->nick) != NULL)
{
log_debug(NAME, "[%s] Extended presence - Nick Change", FZONE);
result = add_extended_presence(from, to, node, STATUS_MUC_NICKCHANGE, NULL, NULL);
}
else
{
log_debug(NAME, "[%s] Extended presence", FZONE);
result = add_extended_presence(from, to, node, status, reason, actor);
}
deliver(dpacket_new(result), NULL);
xmlnode_free(node);
}
if(xmlnode_get_data(from->nick) != NULL)
{
status = xmlnode_get_attrib(from->nick,"status");
log_debug(NAME, "[%s] status = %s/%s", FZONE, status, STATUS_MUC_CREATED);
if(j_strcmp(status, STATUS_MUC_CREATED) == 0)
node = add_extended_presence(from, to, NULL, status, NULL, NULL);
else
node = add_extended_presence(from, to, NULL, NULL, NULL, NULL);
element = xmlnode_get_tag(node, "x?xmlns=jabber:x:delay");
if(element)
xmlnode_hide(element);
xmlnode_put_attrib(node, "to", jid_full(to->realid));
fullid = jid_new(xmlnode_pool(node), jid_full(from->localid));
jid_set(fullid, xmlnode_get_data(from->nick), JID_RESOURCE);
xmlnode_put_attrib(node, "from", jid_full(fullid));
deliver(dpacket_new(node), NULL);
}
}
void con_user_nick(cnu user, char *nick, xmlnode data)
{
xmlnode node;
char *status, *reason, *actor;
cnr room = user->room;
log_debug(NAME, "[%s] in room %s changing nick for user %s to %s from %s", FZONE, jid_full(room->id), jid_full(user->realid), nick, xmlnode_get_data(user->nick));
node = xmlnode_new_tag("n");
xmlnode_put_attrib(node, "old", xmlnode_get_data(user->nick));
if (data)
{
status = xmlnode_get_attrib(data, "status");
reason = xmlnode_get_data(data);
actor = xmlnode_get_attrib(data, "actor");
if(status)
xmlnode_put_attrib(node, "status", status);
if(reason)
xmlnode_put_attrib(node, "reason", reason);
if(actor)
xmlnode_put_attrib(node, "actor", actor);
log_debug(NAME, "[%s] status = %s", FZONE, status);
}
xmlnode_insert_cdata(node,nick,-1);
xmlnode_free(user->nick);
user->nick = node;
deliver__flag = 0;
g_hash_table_foreach(room->local, _con_user_nick, (void*)user);
deliver__flag = 1;
deliver(NULL, NULL);
if(room->note_rename != NULL && nick != NULL && xmlnode_get_attrib(node, "old") != NULL && j_strlen(room->note_rename) > 0)
con_room_send(room, jutil_msgnew("groupchat", NULL, NULL, spools(xmlnode_pool(node), xmlnode_get_attrib(node, "old"), " ", room->note_rename, " ", nick, xmlnode_pool(node))), SEND_LEGACY);
}
void _con_user_enter(gpointer key, gpointer data, gpointer arg)
{
cnu from = (cnu)data;
cnu to = (cnu)arg;
xmlnode node;
jid fullid;
if(from == to)
return;
node = add_extended_presence(from, to, NULL, NULL, NULL, NULL);
xmlnode_put_attrib(node, "to", jid_full(to->realid));
fullid = jid_new(xmlnode_pool(node), jid_full(from->localid));
jid_set(fullid, xmlnode_get_data(from->nick), JID_RESOURCE);
xmlnode_put_attrib(node, "from", jid_full(fullid));
deliver(dpacket_new(node), NULL);
}
void con_user_enter(cnu user, char *nick, int created)
{
xmlnode node;
xmlnode message;
char *key;
int h, tflag = 0;
cnr room = user->room;
user->localid = jid_new(user->p, jid_full(room->id));
jid_set(user->localid, shahash(jid_full(user->realid)), JID_RESOURCE);
key = j_strdup(user->localid->resource);
g_hash_table_insert(room->local, key, (void*)user);
room->count++;
log_debug(NAME, "[%s] officiating user %s in room (created = %d) %s as %s/%s", FZONE, jid_full(user->realid), created, jid_full(room->id), nick, user->localid->resource);
if(created == 1)
{
node = xmlnode_new_tag("reason");
xmlnode_put_attrib(node, "status", STATUS_MUC_CREATED);
con_user_nick(user, nick, node);
xmlnode_free(node);
}
else
{
con_user_nick(user, nick, NULL);
}
if(j_strlen(room->description) > 0)
{
message = jutil_msgnew("groupchat", jid_full(user->realid), NULL, room->description);
xmlnode_put_attrib(message,"from", jid_full(room->id));
deliver(dpacket_new(message), NULL);
}
if(is_legacy(user))
{
message = jutil_msgnew("groupchat", jid_full(user->realid), NULL, spools(user->p, "This room supports the MUC protocol.", user->p));
xmlnode_put_attrib(message,"from", jid_full(room->id));
deliver(dpacket_new(message), NULL);
}
if(room->locked > 0)
{
message = jutil_msgnew("groupchat", jid_full(user->realid), NULL, spools(user->p, "This room is locked from entry until configuration is confirmed.", user->p));
xmlnode_put_attrib(message,"from", jid_full(room->id));
deliver(dpacket_new(message), NULL);
}
g_hash_table_foreach(room->local, _con_user_enter, (void*)user);
deliver__flag = 0;
if(room->master->history > 0)
{
h = room->hlast;
while(1)
{
h++;
if(h == room->master->history)
h = 0;
_con_user_history_send(user, xmlnode_dup(room->history[h]));
if(xmlnode_get_tag(room->history[h],"subject") != NULL)
tflag = 1;
if(h == room->hlast)
break;
}
}
deliver__flag = 1;
deliver(NULL, NULL);
if(tflag == 0 && room->topic != NULL)
{
node = jutil_msgnew("groupchat", jid_full(user->realid), xmlnode_get_attrib(room->topic,"subject"), xmlnode_get_data(room->topic));
xmlnode_put_attrib(node, "from", jid_full(room->id));
deliver(dpacket_new(node), NULL);
}
if(room->note_join != NULL && j_strlen(room->note_join) > 0)
con_room_send(room, jutil_msgnew("groupchat", NULL, NULL, spools(user->p, nick, " ", room->note_join, user->p)), SEND_LEGACY);
if(room->visible == 1)
con_send_alert(user, NULL, NULL, STATUS_MUC_SHOWN_JID);
}
void con_user_process(cnu to, cnu from, jpacket jp)
{
xmlnode node, element;
cnr room = to->room;
char str[10];
int t;
if(jp->type == JPACKET_IQ)
{
if(NSCHECK(jp->iq,NS_BROWSE))
{
jutil_iqresult(jp->x);
node = xmlnode_insert_tag(jp->x, "item");
xmlnode_put_attrib(node, "category", "user");
xmlnode_put_attrib(node, "xmlns", NS_BROWSE);
xmlnode_put_attrib(node, "name", xmlnode_get_data(to->nick));
element = xmlnode_insert_tag(node, "item");
xmlnode_put_attrib(element, "category", "user");
if(room->visible == 1 || is_moderator(room, from->realid))
xmlnode_put_attrib(element, "jid", jid_full(to->realid));
else
xmlnode_put_attrib(element, "jid", jid_full(to->localid));
if(is_legacy(to))
xmlnode_insert_cdata(xmlnode_insert_tag(node, "ns"), NS_GROUPCHAT, -1);
else
xmlnode_insert_cdata(xmlnode_insert_tag(node, "ns"), NS_MUC, -1);
deliver(dpacket_new(jp->x), NULL);
return;
}
if(NSCHECK(jp->iq,NS_LAST))
{
jutil_iqresult(jp->x);
node = xmlnode_insert_tag(jp->x, "query");
xmlnode_put_attrib(node, "xmlns", NS_LAST);
t = time(NULL) - to->last;
sprintf(str,"%d",t);
xmlnode_put_attrib(node ,"seconds", str);
deliver(dpacket_new(jp->x), NULL);
return;
}
if(to->private == 1)
{
jutil_error(jp->x, TERROR_FORBIDDEN);
deliver(dpacket_new(jp->x), NULL);
return;
}
}
if(jp->type == JPACKET_MESSAGE)
{
if(jp->subtype == JPACKET__GROUPCHAT)
{
jutil_error(jp->x, TERROR_BAD);
deliver(dpacket_new(jp->x), NULL);
return;
}
if(room->privmsg == 1 && !is_admin(room, from->realid))
{
if(xmlnode_get_tag(jp->x, "body") != NULL)
{
jutil_error(jp->x, TERROR_MUC_PRIVMSG);
deliver(dpacket_new(jp->x), NULL);
return;
}
else
{
xmlnode_free(jp->x);
return;
}
}
}
con_user_send(to, from, jp->x);
}
void con_user_send(cnu to, cnu from, xmlnode node)
{
jid fullid;
if(to == NULL || from == NULL || node == NULL)
{
return;
}
fullid = jid_new(xmlnode_pool(node), jid_full(from->localid));
xmlnode_put_attrib(node, "to", jid_full(to->realid));
if(xmlnode_get_attrib(node, "cnu") != NULL)
xmlnode_hide_attrib(node, "cnu");
jid_set(fullid, xmlnode_get_data(from->nick), JID_RESOURCE);
xmlnode_put_attrib(node, "from", jid_full(fullid));
deliver(dpacket_new(node), NULL);
}
void con_user_zap(cnu user, xmlnode data)
{
cnr room;
char *reason;
char *status;
char *key;
if(user == NULL || data == NULL)
{
log_warn(NAME, "Aborting: NULL attribute found", FZONE);
if(data != NULL)
xmlnode_free(data);
return;
}
user->leaving = 1;
key = pstrdup(user->p, jid_full(user->realid));
status = xmlnode_get_attrib(data, "status");
reason = xmlnode_get_data(data);
room = user->room;
if(room == NULL)
{
log_warn(NAME, "[%s] Unable to zap user %s <%s-%s> : Room does not exist", FZONE, jid_full(user->realid), status, reason);
xmlnode_free(data);
return;
}
log_debug(NAME, "[%s] zapping user %s <%s-%s>", FZONE, jid_full(user->realid), status, reason);
if(user->localid != NULL)
{
con_user_nick(user, NULL, data);
log_debug(NAME, "[%s] Removing entry from local list", FZONE);
g_hash_table_remove(room->local, user->localid->resource);
room->count--;
if(room->note_leave != NULL && j_strlen(room->note_leave) > 0)
{
if(reason != NULL)
{
if(j_strcmp(status, STATUS_MUC_KICKED) == 0)
{
con_room_send(room,jutil_msgnew("groupchat",NULL,NULL,spools(user->p, xmlnode_get_attrib(user->nick,"old")," ",room->note_leave,": [Kicked] ", reason, user->p)), SEND_LEGACY);
}
else if(j_strcmp(status, STATUS_MUC_BANNED) == 0)
{
con_room_send(room,jutil_msgnew("groupchat",NULL,NULL,spools(user->p,xmlnode_get_attrib(user->nick,"old")," ",room->note_leave,": [Banned] ", reason, user->p)), SEND_LEGACY);
}
else
{
con_room_send(room,jutil_msgnew("groupchat",NULL,NULL,spools(user->p,xmlnode_get_attrib(user->nick,"old")," ",room->note_leave,": ", reason, user->p)), SEND_LEGACY);
}
}
else
{
con_room_send(room,jutil_msgnew("groupchat",NULL,NULL,spools(user->p,xmlnode_get_attrib(user->nick,"old")," ",room->note_leave,user->p)), SEND_LEGACY);
}
}
}
xmlnode_free(data);
log_debug(NAME, "[%s] Removing any affiliate info from admin list", FZONE);
log_debug(NAME, "[%s] admin list size [%d]", FZONE, g_hash_table_size(room->admin));
remove_affiliate(room->admin, user->realid);
log_debug(NAME, "[%s] Removing any affiliate info from member list", FZONE);
log_debug(NAME, "[%s] member list size [%d]", FZONE, g_hash_table_size(room->member));
remove_affiliate(room->member, user->realid);
log_debug(NAME, "[%s] Removing any role info from moderator list", FZONE);
log_debug(NAME, "[%s] moderator list size [%d]", FZONE, g_hash_table_size(room->moderator));
revoke_role(room->moderator, user);
log_debug(NAME, "[%s] Removing any role info from participant list", FZONE);
log_debug(NAME, "[%s] participant list size [%d]", FZONE, g_hash_table_size(room->participant));
revoke_role(room->participant, user);
log_debug(NAME, "[%s] Removing any roster info from roster list", FZONE);
remove_roster(room, user->realid);
log_debug(NAME, "[%s] Un-alloc presence xmlnode", FZONE);
xmlnode_free(user->presence);
log_debug(NAME, "[%s] Un-alloc nick xmlnode", FZONE);
xmlnode_free(user->nick);
log_debug(NAME, "[%s] Un-alloc history xmlnode", FZONE);
xmlnode_free(user->history);
log_debug(NAME, "[%s] Removing from remote list and un-alloc cnu", FZONE);
g_hash_table_remove(room->remote, jid_full(user->realid));
}