📄 conference.c
字号:
if(room->invitation == 1 && !is_member(room, u->realid) && !is_owner(room, u->realid))
{
jutil_error(jp->x, TERROR_MUC_INVITED);
deliver(dpacket_new(jp->x),NULL);
return;
}
/* Room is full, return full room error */
if(room->count >= room->maxusers && room->maxusers != 0 && !is_admin(room, u->realid))
{
log_debug(NAME, "[%s] Room over quota - disallowing entry", FZONE);
jutil_error(jp->x, TERROR_MUC_FULL);
deliver(dpacket_new(jp->x),NULL);
return;
}
/* Room has been locked against entry */
if(room->locked && !is_owner(room, u->realid))
{
log_debug(NAME, "[%s] Room has been locked", FZONE);
jutil_error(jp->x, TERROR_NOTFOUND);
deliver(dpacket_new(jp->x),NULL);
return;
}
/* User already in room, simply a nick change */
if(u->localid != NULL)
{
xmlnode_free(u->presence);
u->presence = xmlnode_dup(jp->x);
con_user_nick(u, jp->to->resource, NULL); /* broadcast nick rename */
xmlnode_free(jp->x);
return;
}
else if(room->secret == NULL || is_sadmin(master, jp->from)) /* No password required, just go right in, or you're an sadmin */
{
if(NSCHECK(xmlnode_get_tag(jp->x,"x"), NS_MUC))
{
/* Set legacy value to room value */
u->legacy = 0;
node = xmlnode_get_tag(jp->x,"x");
xmlnode_hide(node);
/* Enable room defaults automatically */
if(master->roomlock == -1)
{
created = 0;
}
}
else
{
u->legacy = 1;
created = 0; /* Override created flag for non-MUC compliant clients */
}
xmlnode_free(u->presence);
u->presence = xmlnode_dup(jp->x);
jutil_delay(u->presence, NULL);
log_debug(NAME, "[%s] About to enter room, legacy<%d>, presence [%s]", FZONE, u->legacy, xmlnode2str(u->presence));
con_user_enter(u, jp->to->resource, created); /* join the room */
xmlnode_free(jp->x);
return;
}
else if(jp->type == JPACKET_PRESENCE) /* Hopefully you are including a password, this room is locked */
{
if(NSCHECK(xmlnode_get_tag(jp->x,"x"), NS_MUC))
{
log_debug(NAME, "[%s] Password?", FZONE);
if(j_strcmp(room->secret, xmlnode_get_tag_data(xmlnode_get_tag(jp->x,"x"), "password")) == 0)
{
/* Set legacy value to room value */
u->legacy = 0;
node = xmlnode_get_tag(jp->x,"x");
xmlnode_hide(node);
xmlnode_free(u->presence);
u->presence = xmlnode_dup(jp->x);
jutil_delay(u->presence, NULL);
con_user_enter(u, jp->to->resource, created); /* join the room */
xmlnode_free(jp->x);
return;
}
}
}
/* No password found, room is password protected. Return password error */
jutil_error(jp->x, TERROR_MUC_PASSWORD);
deliver(dpacket_new(jp->x), NULL);
return;
}
/* kill any user sending unavailable presence */
if(jpacket_subtype(jp) == JPACKET__UNAVAILABLE)
{
if(u != NULL)
{
reason = xmlnode_get_tag_data(jp->x, "status");
xmlnode_free(u->presence);
u->presence = xmlnode_dup(jp->x);
node = xmlnode_new_tag("reason");
if (reason)
xmlnode_insert_cdata(node, reason, -1);
con_user_zap(u, node);
}
xmlnode_free(jp->x);
return;
}
/* handle errors */
if(jpacket_subtype(jp) == JPACKET__ERROR)
{
/* only allow iq errors that are to a resource (direct-chat) */
if(jp->to->resource == NULL || jp->type != JPACKET_IQ)
{
if(u != NULL && u->localid != NULL)
{
log_debug(NAME, "[%s] Error Handler: Zapping user", FZONE);
node = xmlnode_new_tag("reason");
xmlnode_insert_cdata(node, "Lost connection", -1);
con_user_zap(u, node);
}
else
{
log_debug(NAME, "[%s] Error Handler: No cnu/lid found for user", FZONE);
}
}
xmlnode_free(jp->x);
return;
}
/* not in the room yet? foo */
if(u == NULL || u->localid == NULL)
{
if(u == NULL)
{
log_debug(NAME, "[%s] No cnu found for user", FZONE);
}
else
{
log_debug(NAME, "[%s] No lid found for %s", FZONE, jid_full(jid_fix(u->realid)));
}
if(jp->to->resource != NULL)
{
jutil_error(jp->x, TERROR_NOTFOUND);
deliver(dpacket_new(jp->x),NULL);
return;
}
else
{
con_room_outsider(room, u, jp); /* non-participants get special treatment */
}
return;
}
/* packets to a specific resource? one on one chats, browse lookups, etc */
if(jp->to->resource != NULL)
{
if((u2 = htb_get(&room->local, jp->to->resource)) == NULL && (u2 = con_room_usernick(room, jp->to->resource)) == NULL) /* gotta have a recipient */
{
jutil_error(jp->x, TERROR_NOTFOUND);
deliver(dpacket_new(jp->x),NULL);
return;
}
else
{
con_user_process(u2, u, jp);
}
return;
}
/* finally, handle packets just to a room from a participant, msgs, pres, iq browse/conferencing, etc */
con_room_process(room, u, jp);
}
/* phandler callback, send packets to another server */
result con_packets(instance i, dpacket dp, void *arg)
{
cni master = (cni)arg;
jpacket jp;
/* routes are from dnsrv w/ the needed ip */
if(dp->type == p_ROUTE)
jp = jpacket_new(xmlnode_get_firstchild(dp->x));
else
jp = jpacket_new(dp->x);
/* if the delivery failed */
if(jp == NULL)
{
deliver_fail(dp,"Illegal Packet");
return r_DONE;
}
/* bad packet??? ick */
if(jp->type == JPACKET_UNKNOWN || jp->to == NULL)
{
jutil_error(jp->x, TERROR_BAD);
deliver(dpacket_new(jp->x),NULL);
return r_DONE;
}
/* we want things processed in order, and don't like re-entrancy! */
jp->aux1 = (void*)master;
mtq_send(master->q, jp->p, _con_packets, (void *)jp);
return r_DONE;
}
void _con_shutdown_rooms(const char *key, void *data, void *arg)
{
cnr room = (cnr)data;
con_room_cleanup(room);
}
void con_shutdown(void *arg)
{
cni master = (cni)arg;
log_debug(NAME, "[%s] SHUTDOWN: Clearing configuration", FZONE);
xmlnode_free(master->config);
log_debug(NAME, "[%s] SHUTDOWN: Zapping sadmin table", FZONE);
htb_free(&master->sadmin);
log_debug(NAME, "[%s] SHUTDOWN: Clear users from rooms", FZONE);
htb_walk(&master->rooms, _con_shutdown_rooms, NULL);
log_debug(NAME, "[%s] SHUTDOWN: Zapping rooms", FZONE);
htb_free(&master->rooms);
log_debug(NAME, "[%s] SHUTDOWN: Sequence completed", FZONE);
}
/* callback for walking each user in a room */
void _con_beat_user(const char *key, void *data, void *arg)
{
cnu user = (cnu)data;
int now = (int)arg;
xmlnode node;
if(user->localid == NULL && (now - user->last) > 120)
{
log_debug(NAME, "[%s] Removing zombie", FZONE);
node = xmlnode_new_tag("reason");
xmlnode_insert_cdata(node, "Clearing zombie", -1);
con_user_zap(user, node);
}
}
/* callback for walking each room */
void _con_beat_idle(const char *key, void *data, void *arg)
{
cnr room = (cnr)data;
int now = (int)arg;
htb_walk(&room->remote, _con_beat_user, arg); /* makes sure nothing stale is in the room */
if(room->persistant == 0 && room->count == 0 && (now - room->last) > 240)
con_room_zap(room);
}
/* heartbeat checker for timed out idle rooms */
void _con_beat_logrotate(const char *key, void *data, void *arg)
{
cnr room = (cnr)data;
if(room->logfile)
{
log_debug(NAME, "[%s] Rotating log for room %s", FZONE, jid_full(jid_fix(room->id)));
con_room_log_close(room);
con_room_log_new(room);
}
}
/* heartbeat checker for timed out idle rooms */
void _con_beat_logupdate(const char *key, void *data, void *arg)
{
cnr room = (cnr)data;
char *timestamp = (char*)arg;
if(room->logformat == LOG_XHTML && room->logfile)
{
log_debug(NAME, "[%s] Adding anchor >%s< for room %s", FZONE, timestamp, jid_full(jid_fix(room->id)));
fprintf(room->logfile, "<a name=\"%s\"></a>\n", timestamp);
fflush(room->logfile);
}
}
/* heartbeat checker for maintainance */
result con_beat_update(void *arg)
{
cni master = (cni)arg;
time_t t = time(NULL);
int mins = minuteget(t);
char *tstamp = timeget(t);
char *dstamp = dateget(t);
/* Check for timed out idle rooms */
if(mins % 2 == 0)
{
htb_walk(&master->rooms, _con_beat_idle,(void*)t);
}
/* Check for logfiles requiring updating */
if(mins % 5 == 0)
{
htb_walk(&master->rooms,_con_beat_logupdate,(void*)tstamp);
free(tstamp);
}
if(j_strcmp(master->day, dstamp) == 0)
{
free(dstamp);
return r_DONE;
}
master->day = pstrdup(master->i->p, dstamp);
free(dstamp);
htb_walk(&master->rooms, _con_beat_logrotate, NULL);
return r_DONE;
}
/* heartbeat checker for miscellaneous tasks */
result con_beat_housekeep(void *arg)
{
cni master = (cni)arg;
master->loader = 1;
xdb_rooms_get(master);
/* Remove unwanted heartbeat */
return r_UNREG;
}
/*** everything starts here ***/
void conference(instance i, xmlnode x)
{
cni master;
xmlnode cfg;
jid sadmin;
xmlnode current;
xmlnode node;
time_t now = time(NULL);
log_debug(NAME, "[%s] mu-conference loading %s %d", FZONE, i->id, i->type);
/* Allocate space for cni struct and link to instance */
log_debug(NAME, "[%s] Malloc: _cni=%d", FZONE, sizeof(_cni));
master = pmalloco(i->p, sizeof(_cni));
master->i = i;
/* Set up xdb interface */
master->xdbc = xdb_cache(i);
/* get the config */
cfg = xdb_get(master->xdbc, jid_new(xmlnode_pool(x), "config@-internal"), "jabber:config:conference");
/* Parse config and initialise variables */
master->q = mtq_new(i->p);
master->maxhash = j_atoi(xmlnode_get_tag_data(cfg,"maxhash"),401);
/* Check Hash size is prime */
if(isPrime(master->maxhash))
{
log_debug(NAME, "[%s] Prime check passed", FZONE);
}
else
{
log_debug(NAME, "[%s] Prime check failed - setting to 401", FZONE);
master->maxhash = 401;
}
master->loader = 0;
master->start = now;
htb_init_table(&master->rooms, master->maxhash);
master->history = j_atoi(xmlnode_get_tag_data(cfg,"history"),10);
master->config = cfg; /* Store a copy of the config for later usage */
master->day = pstrdup(i->p, dateget(now)); /* Used to determine when to rotate logs */
master->logdir = xmlnode_get_tag_data(cfg, "logdir"); /* Directory where to store logs */
/* If requested, set default room state to 'public', otherwise will default to 'private */
if(xmlnode_get_tag(cfg,"public"))
master->public = 1;
/* If requested, rooms are given a default configuration */
if(xmlnode_get_tag(cfg,"defaults"))
master->roomlock = -1;
/* If requested, stop any new rooms being created */
if(xmlnode_get_tag(cfg,"roomlock"))
master->roomlock = 1;
/* If requested, stop any new rooms being created */
if(xmlnode_get_tag(cfg,"dynamic"))
master->dynamic = 1;
/* If requested, stop any new rooms being created */
if(xmlnode_get_tag(cfg,"persistent"))
master->dynamic = -1;
htb_init_table(&master->sadmin, master->maxhash);
/* sadmin code */
if(xmlnode_get_tag(cfg, "sadmin"))
{
node = xmlnode_get_tag(cfg, "sadmin");
for(current = xmlnode_get_firstchild(node); current != NULL; current = xmlnode_get_nextsibling(current))
{
sadmin = jid_new(i->p, xmlnode_get_data(current));
if(sadmin != NULL)
{
log_debug(NAME, "[%s] Adding sadmin %s", FZONE, jid_full(sadmin));
htb_put(&master->sadmin, jid_full(jid_user(jid_fix(sadmin))), (void*)1);
}
}
}
register_phandler(i, o_DELIVER, con_packets, (void*)master);
register_shutdown(con_shutdown,(void *) master);
register_beat(60, con_beat_update, (void *)master);
register_beat(1, con_beat_housekeep, (void *)master);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -