mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 15:15:10 +00:00
268 lines
6.5 KiB
C
268 lines
6.5 KiB
C
#include <XMPPCommand.h>
|
|
|
|
#include <Cytoplasm/HashMap.h>
|
|
#include <Cytoplasm/Memory.h>
|
|
#include <Cytoplasm/Util.h>
|
|
#include <Cytoplasm/Str.h>
|
|
#include <Cytoplasm/Log.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
typedef struct XMPPSession {
|
|
char *identifier;
|
|
|
|
/* "Each session [...] SHOULD be valid only between one
|
|
* requester/responder pair." */
|
|
/* The Parsee-managed entity managing the session. */
|
|
char *receiver;
|
|
/* The command's issuer entity. */
|
|
char *issuer;
|
|
|
|
/* The issued node */
|
|
char *node;
|
|
/* Timestamp of the session's creation, from Parsee's
|
|
* point-of-view */
|
|
uint64_t creation;
|
|
} XMPPSession;
|
|
|
|
struct XMPPCommandManager {
|
|
pthread_mutex_t lock;
|
|
|
|
/* A hashmap of XMPPCommands. */
|
|
HashMap *commands;
|
|
|
|
HashMap *sessions;
|
|
|
|
void *cookie;
|
|
};
|
|
static void
|
|
XMPPDestroySession(XMPPSession *session)
|
|
{
|
|
if (!session)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Free(session->identifier);
|
|
Free(session->receiver);
|
|
Free(session->issuer);
|
|
Free(session->node);
|
|
Free(session);
|
|
}
|
|
|
|
static void
|
|
InvalidateSession(XMPPCommandManager *m, char *session)
|
|
{
|
|
XMPPSession *s = HashMapDelete(m->sessions, session);
|
|
XMPPDestroySession(s);
|
|
}
|
|
|
|
static char *
|
|
NewSession(XMPPCommandManager *m, char *node)
|
|
{
|
|
char *session_id = NULL;
|
|
do
|
|
{
|
|
int period = (UtilTsMillis() / (10 SECONDS));
|
|
char *rand = StrRandom(16);
|
|
char *pstr = StrInt(period);
|
|
session_id = StrConcat(5, node, "_", pstr, "_", rand);
|
|
|
|
Free(rand);
|
|
Free(pstr);
|
|
}
|
|
while (HashMapGet(m->sessions, session_id));
|
|
|
|
return session_id;
|
|
}
|
|
/* NOTE: The manager MUST be locked. */
|
|
static char *
|
|
XMPPRegisterSession(XMPPCommandManager *m, char *p_jid, char *s_jid, char *node)
|
|
{
|
|
XMPPSession *session;
|
|
char *session_ident;
|
|
if (!m || !p_jid || !s_jid)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
session = Malloc(sizeof(*session));
|
|
session->node = StrDuplicate(node);
|
|
session->issuer = StrDuplicate(s_jid);
|
|
session->receiver = StrDuplicate(p_jid);
|
|
session->creation = UtilTsMillis();
|
|
session_ident = NewSession(m, node);
|
|
session->identifier = session_ident;
|
|
|
|
HashMapSet(m->sessions, session_ident, session);
|
|
|
|
return session_ident;
|
|
}
|
|
|
|
|
|
XMPPCommandManager *
|
|
XMPPCreateManager(void *cookie)
|
|
{
|
|
XMPPCommandManager *ret = Malloc(sizeof(*ret));
|
|
|
|
pthread_mutex_init(&ret->lock, NULL);
|
|
ret->commands = HashMapCreate();
|
|
ret->sessions = HashMapCreate();
|
|
ret->cookie = cookie;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
XMPPRegisterCommand(XMPPCommandManager *m, XMPPCommand *cmd)
|
|
{
|
|
if (!m || !cmd)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&m->lock);
|
|
HashMapSet(m->commands, XMPPGetCommandNode(cmd), cmd);
|
|
pthread_mutex_unlock(&m->lock);
|
|
}
|
|
|
|
void
|
|
XMPPFreeManager(XMPPCommandManager *manager)
|
|
{
|
|
char *node_name, *session_id;
|
|
XMPPCommand *val;
|
|
XMPPSession *session;
|
|
if (!manager)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while (HashMapIterate(manager->commands, &node_name, (void **) &val))
|
|
{
|
|
XMPPFreeCommand(val);
|
|
}
|
|
while (HashMapIterate(manager->sessions, &session_id, (void **) &session))
|
|
{
|
|
XMPPDestroySession(session);
|
|
}
|
|
|
|
pthread_mutex_destroy(&manager->lock);
|
|
HashMapFree(manager->commands);
|
|
HashMapFree(manager->sessions);
|
|
Free(manager);
|
|
}
|
|
void
|
|
XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p)
|
|
{
|
|
char *node_name;
|
|
XMPPCommand *val;
|
|
XMLElement *item;
|
|
if (!m || !p || !jid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pthread_mutex_lock(&m->lock);
|
|
while (HashMapIterate(m->commands, &node_name, (void **) &val))
|
|
{
|
|
item = XMLCreateTag("item");
|
|
XMLAddAttr(item, "jid", jid);
|
|
XMLAddAttr(item, "node", node_name);
|
|
XMLAddAttr(item, "name", XMPPGetCommandDesc(val));
|
|
XMLAddChild(p, item);
|
|
}
|
|
pthread_mutex_unlock(&m->lock);
|
|
}
|
|
bool
|
|
XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
|
|
{
|
|
XMLElement *command;
|
|
XMPPComponent *jabber;
|
|
XMPPCommand *cmd;
|
|
char *from, *to, *id;
|
|
char *session_id = NULL;
|
|
bool good = false;
|
|
if (!m || !stanza || !data)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
jabber = data->jabber;
|
|
|
|
from = HashMapGet(stanza->attrs, "from");
|
|
to = HashMapGet(stanza->attrs, "to");
|
|
id = HashMapGet(stanza->attrs, "id");
|
|
|
|
pthread_mutex_lock(&m->lock);
|
|
|
|
/* TODO */
|
|
#define CMD_NS "http://jabber.org/protocol/commands"
|
|
if ((command = XMLookForTKV(stanza, "command", "xmlns", CMD_NS)))
|
|
{
|
|
char *action = HashMapGet(command->attrs, "action");
|
|
char *node = HashMapGet(command->attrs, "node");
|
|
|
|
if (!action || StrEquals(action, "execute"))
|
|
{
|
|
XMLElement *command_xml, *iq;
|
|
/* This is an execution. */
|
|
cmd = HashMapGet(m->commands, node);
|
|
|
|
if (!cmd)
|
|
{
|
|
Log(LOG_WARNING,
|
|
"User %s asked to execute '%s', but it doesn't exist.",
|
|
from, node
|
|
);
|
|
goto end;
|
|
}
|
|
|
|
if (XMPPCommandRequiresForm(cmd))
|
|
{
|
|
Log(LOG_WARNING,
|
|
"User %s asked to execute '%s', but it requires a form, "
|
|
"which is currently UNIMPLEMENTED", from, node
|
|
);
|
|
goto end;
|
|
}
|
|
|
|
/* Doesn't need to be freed, as it lives with m. */
|
|
session_id = XMPPRegisterSession(m, to, from, node);
|
|
|
|
/* No forms, we good. */
|
|
iq = XMLCreateTag("iq");
|
|
XMLAddAttr(iq, "type", "result");
|
|
XMLAddAttr(iq, "from", to);
|
|
XMLAddAttr(iq, "to", from);
|
|
XMLAddAttr(iq, "id", id);
|
|
command_xml = XMLCreateTag("command");
|
|
XMLAddAttr(command_xml, "xmlns", CMD_NS);
|
|
XMLAddAttr(command_xml, "node", node);
|
|
XMLAddAttr(command_xml, "status", "completed");
|
|
XMLAddAttr(command_xml, "sessionid", session_id);
|
|
XMPPExecuteCommand(m, cmd, from, command_xml, NULL);
|
|
XMLAddChild(iq, command_xml);
|
|
|
|
pthread_mutex_lock(&jabber->write_lock);
|
|
XMLEncode(jabber->stream, iq);
|
|
StreamFlush(jabber->stream);
|
|
pthread_mutex_unlock(&jabber->write_lock);
|
|
XMLFreeElement(iq);
|
|
|
|
InvalidateSession(m, session_id);
|
|
|
|
good = true;
|
|
goto end;
|
|
}
|
|
}
|
|
#undef CMD_NS
|
|
|
|
end:
|
|
pthread_mutex_unlock(&m->lock);
|
|
return good;
|
|
}
|
|
void *
|
|
XMPPGetManagerCookie(XMPPCommandManager *manager)
|
|
{
|
|
return manager ? manager->cookie : NULL;
|
|
}
|