/** * send presence * type - "unavailable", "subscribe", "subscribed" .... * status - "online", "away", "unavailable" ... * priority - "0", "1", ... */ int xj_jcon_send_presence(xj_jcon jbc, char *sto, char *type, char *status, char *priority) { char *p; int n; xode x, y; if(jbc == NULL) return -1; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_jcon_send_presence: -----START-----\n"); #endif x = xode_new_tag("presence"); if(!x) return -1; if(sto != NULL) xode_put_attrib(x, "to", sto); if(type != NULL) xode_put_attrib(x, "type", type); if(status != NULL) { y = xode_insert_tag(x, "status"); xode_insert_cdata(y, status, strlen(status)); } if(priority != NULL) { y = xode_insert_tag(x, "priority"); xode_insert_cdata(y, priority, strlen(priority)); } p = xode_to_str(x); n = strlen(p); if(send(jbc->sock, p, n, 0) != n) { DBG("XJAB:xj_jcon_send_presence: Error - presence not sent\n"); goto error; } xode_free(x); #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_jcon_send_presence: presence status was sent\n"); #endif return 0; error: xode_free(x); return -1; }
static void _xode_expat_charData(void* userdata, const char* s, int len) { xode *x = userdata; xode current = *x; xode_insert_cdata(current, s, len); }
tt_user *users_save(const char *jid) { tt_user **user, *user0; xode cfg, x; char *file; if (jid == NULL) return NULL; if ((file = malloc(strlen(config_dir) + strlen(jid) + 2)) == NULL) { perror("malloc()"); exit(1); } sprintf(file, "%s/%s", config_dir, jid); my_debug(0, "users: Zapisuje plik %s", file); user = jid_jid2user(jid); user0 = *user; cfg = xode_new("user"); x = xode_insert_tag(cfg, "jid"); xode_insert_cdata(x, user0->jid, -1); x = xode_insert_tag(cfg, "tid"); xode_insert_cdata(x, user0->tid_short, -1); x = xode_insert_tag(cfg, "password"); xode_insert_cdata(x, user0->password, -1); x = xode_insert_tag(cfg, "notify"); xode_put_attrib(x, "mail", (user0->mailnotify ? "1" : "0")); xode_put_attrib(x, "typing", (user0->typingnotify ? "1" : "0")); xode_put_attrib(x, "alarm", (user0->alarmnotify ? "1" : "0")); xode_to_file(file, cfg); xode_free(cfg); t_free(file); return user0; }
static void _xode_stream_charData(xode_stream xs, const char *str, int len) { /* if xode_stream is bad, get outa here */ if(xs->status > XODE_STREAM_NODE) return; if(xs->node == NULL) { /* we must be in the root of the stream where CDATA is irrelevant */ return; } xode_insert_cdata(xs->node, str, len); }
/** * send a message through a JABBER connection * params are pairs (buffer, len) */ int xj_jcon_send_msg(xj_jcon jbc, char *to, int tol, char *msg, int msgl, int type) { char msg_buff[4096], *p; int n; xode x; if(jbc == NULL) return -1; x = xode_new_tag("body"); if(!x) return -1; xode_insert_cdata(x, msg, msgl); x = xode_wrap(x, "message"); strncpy(msg_buff, to, tol); msg_buff[tol] = 0; xode_put_attrib(x, "to", msg_buff); switch(type) { case XJ_JMSG_CHAT: xode_put_attrib(x, "type", "chat"); break; case XJ_JMSG_GROUPCHAT: xode_put_attrib(x, "type", "groupchat"); break; default: xode_put_attrib(x, "type", "normal"); } p = xode_to_str(x); n = strlen(p); #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_jcon_send_msg: jabber msg:\n%s\n", p); #endif if(send(jbc->sock, p, n, 0) != n) { DBG("XJAB:xj_jcon_send_msg: error - message not sent\n"); goto error; } xode_free(x); return 0; error: xode_free(x); return -1; }
static void do_send_message_server(struct xmpp_pipe_cmd *cmd) { char *domain; xode x; LM_DBG("rom=[%s] to=[%s] body=[%s]\n", cmd->from,cmd->to, cmd->body); x = xode_new_tag("message"); xode_put_attrib(x, "xmlns", "jabber:client"); xode_put_attrib(x, "id", cmd->id); // XXX xode_put_attrib(x, "from", encode_uri_sip_xmpp(cmd->from)); xode_put_attrib(x, "to", decode_uri_sip_xmpp(cmd->to)); xode_put_attrib(x, "type", "chat"); xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1); domain = extract_domain(decode_uri_sip_xmpp(cmd->to)); xode_send_domain(domain, x); }
/* attempts to parse the buff onto this stream firing events to the handler, returns the last known status */ int xode_stream_eat(xode_stream xs, char *buff, int len) { char *err; xode xerr; static char maxerr[] = "maximum node size reached"; static char deeperr[] = "maximum node depth reached"; if(xs == NULL) { fprintf(stderr,"Fatal Programming Error: xode_streameat() was improperly called with NULL.\n"); return XODE_STREAM_ERROR; } if(len == 0 || buff == NULL) return xs->status; if(len == -1) /* easy for hand-fed eat calls */ len = strlen(buff); if(!XML_Parse(xs->parser, buff, len, 0)) { err = (char *)XML_ErrorString(XML_GetErrorCode(xs->parser)); xs->status = XODE_STREAM_ERROR; }else if(xode_pool_size(xode_get_pool(xs->node)) > XODE_STREAM_MAXNODE || xs->cdata_len > XODE_STREAM_MAXNODE){ err = maxerr; xs->status = XODE_STREAM_ERROR; }else if(xs->status == XODE_STREAM_ERROR){ /* set within expat handlers */ err = deeperr; }else{ err = deeperr; } /* fire parsing error event, make a node containing the error string */ if(xs->status == XODE_STREAM_ERROR) { xerr = xode_new("error"); xode_insert_cdata(xerr,err,-1); (xs->f)(XODE_STREAM_ERROR, xerr, xs->arg); } return xs->status; }
/*! * */ static int do_send_message_component(struct xmpp_private_data *priv, struct xmpp_pipe_cmd *cmd) { xode x; LM_DBG("do_send_message_component from=[%s] to=[%s] body=[%s]\n", cmd->from, cmd->to, cmd->body); x = xode_new_tag("message"); xode_put_attrib(x, "id", cmd->id); // XXX xode_put_attrib(x, "from", encode_uri_sip_xmpp(cmd->from)); xode_put_attrib(x, "to", decode_uri_sip_xmpp(cmd->to)); xode_put_attrib(x, "type", "chat"); xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1); xode_send(priv->fd, x); xode_free(x); /* missing error handling here ?!?!*/ return 0; }
/* places copy of node and node's siblings in parent */ void xode_insert_node(xode parent, xode node) { if(node == NULL || parent == NULL) return; while(node != NULL) { switch(xode_get_type(node)) { case XODE_TYPE_ATTRIB: xode_put_attrib(parent, xode_get_name(node), xode_get_data(node)); break; case XODE_TYPE_TAG: xode_insert_tagnode(parent, node); break; case XODE_TYPE_CDATA: xode_insert_cdata(parent, xode_get_data(node), xode_get_datasz(node)); } node = xode_get_nextsibling(node); } }
static void stream_node_callback(int type, xode node, void *arg) { struct xmpp_private_data *priv = (struct xmpp_private_data *) arg; char *id, *hash, *tag; char buf[4096]; xode x; LM_DBG("stream callback: %d: %s\n", type, node ? xode_get_name(node) : "n/a"); switch (type) { case XODE_STREAM_ROOT: id = xode_get_attrib(node, "id"); snprintf(buf, sizeof(buf), "%s%s", id, xmpp_password); hash = shahash(buf); x = xode_new_tag("handshake"); xode_insert_cdata(x, hash, -1); xode_send(priv->fd, x); xode_free(x); break; case XODE_STREAM_NODE: tag = xode_get_name(node); if (!strcmp(tag, "handshake")) { LM_DBG("handshake succeeded\n"); } else if (!strcmp(tag, "message")) { LM_DBG("XMPP IM received\n"); char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *type = xode_get_attrib(node, "type"); xode body = xode_get_tag(node, "body"); char *msg; if (!type) type = "chat"; if (!strcmp(type, "error")) { LM_DBG("received message error stanza\n"); goto out; } if (!from || !to || !body) { LM_DBG("invalid <message/> attributes\n"); goto out; } if (!(msg = xode_get_data(body))) msg = ""; xmpp_send_sip_msg( encode_uri_xmpp_sip(from), decode_uri_xmpp_sip(to), msg); } else if (!strcmp(tag, "presence")) { /* call presence callbacks */ LM_DBG("XMPP Presence received\n"); run_xmpp_callbacks(XMPP_RCV_PRESENCE, xode_to_str(node)); }else if (!strcmp(tag, "iq")) { /* call presence callbacks */ LM_DBG("XMPP IQ received\n"); run_xmpp_callbacks(XMPP_RCV_IQ, xode_to_str(node)); } break; case XODE_STREAM_ERROR: LM_ERR("stream error\n"); /* fall-through */ case XODE_STREAM_CLOSE: priv->running = 0; break; } out: xode_free(node); }
static void in_stream_node_callback(int type, xode node, void *arg) { struct xmpp_connection *conn = (struct xmpp_connection *) arg; char *tag; xode x; LM_DBG("instream callback: %d: %s\n", type, node ? xode_get_name(node) : "n/a"); switch (type) { case XODE_STREAM_ROOT: conn->stream_id = strdup(random_secret()); net_printf(conn->fd, "<?xml version='1.0'?>" "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' version='1.0'" " xmlns:db='jabber:server:dialback' id='%s' from='%s'>", conn->stream_id, xmpp_domain); net_printf(conn->fd,"<stream:features xmlns:stream='http://etherx.jabber.org/streams'/>"); break; case XODE_STREAM_NODE: tag = xode_get_name(node); if (!strcmp(tag, "db:result")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); /* char *id = xode_get_attrib(node, "id"); */ char *type = xode_get_attrib(node, "type"); char *cdata = xode_get_data(node); if (!type) { if (conn->domain) { LM_DBG("connection %d has old domain '%s'\n",conn->fd, conn->domain); free(conn->domain); } conn->domain = strdup(from); LM_DBG("connection %d set domain '%s'\n", conn->fd, conn->domain); /* it's a request; send verification over outgoing connection */ x = xode_new_tag("db:verify"); xode_put_attrib(x, "xmlns:db", "jabber:server:dialback"); xode_put_attrib(x, "from", to); xode_put_attrib(x, "to", from); //xode_put_attrib(x, "id", "someid"); /* XXX fix ID */ xode_put_attrib(x, "id", conn->stream_id); xode_insert_cdata(x, cdata, -1); xode_send_domain(from, x); } } else if (!strcmp(tag, "db:verify")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *id = xode_get_attrib(node, "id"); char *type = xode_get_attrib(node, "type"); char *cdata = xode_get_data(node); if (!type) { /* it's a request */ x = xode_new_tag("db:verify"); xode_put_attrib(x, "xmlns:db", "jabber:server:dialback"); xode_put_attrib(x, "from", to); xode_put_attrib(x, "to", from); xode_put_attrib(x, "id", id); //if (cdata && !strcmp(cdata, DB_KEY)) { if (cdata && !strcmp(cdata, db_key(local_secret, from, id))) { xode_put_attrib(x, "type", "valid"); } else { xode_put_attrib(x, "type", "invalid"); } xode_send(conn->fd, x); xode_free(x); } } else if (!strcmp(tag, "message")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *type = xode_get_attrib(node, "type"); xode body = xode_get_tag(node, "body"); char *msg; if (!type) type = "chat"; if (!strcmp(type, "error")) { LM_DBG("received message error stanza\n"); goto out; } if (!from || !to || !body) { LM_DBG("invalid <message/> attributes\n"); goto out; } if (!(msg = xode_get_data(body))) msg = ""; xmpp_send_sip_msg( encode_uri_xmpp_sip(from), decode_uri_xmpp_sip(to), msg); } else if (!strcmp(tag, "presence")) { /* run presence callbacks */ } break; break; case XODE_STREAM_ERROR: LM_ERR("instream error\n"); /* fall-through */ case XODE_STREAM_CLOSE: conn->type = CONN_DEAD; break; } out: xode_free(node); }
static void out_stream_node_callback(int type, xode node, void *arg) { struct xmpp_connection *conn = (struct xmpp_connection *) arg; struct xmpp_connection *in_conn = NULL; char *tag; xode x; LM_DBG("outstream callback: %d: %s\n", type, node?xode_get_name(node):"n/a"); if (conn->domain) in_conn = conn_find_domain(conn->domain, CONN_INBOUND); switch (type) { case XODE_STREAM_ROOT: x = xode_new_tag("db:result"); xode_put_attrib(x, "xmlns:db", "jabber:server:dialback"); xode_put_attrib(x, "from", xmpp_domain); xode_put_attrib(x, "to", conn->domain); //xode_insert_cdata(x, DB_KEY, -1); xode_insert_cdata(x, db_key(local_secret, conn->domain, xode_get_attrib(node, "id")), -1); xode_send(conn->fd, x); xode_free(x); break; case XODE_STREAM_NODE: tag = xode_get_name(node); if (!strcmp(tag, "db:verify")) { char *from = xode_get_attrib(node, "from"); char *to = xode_get_attrib(node, "to"); char *id = xode_get_attrib(node, "id"); char *type = xode_get_attrib(node, "type"); /* char *cdata = xode_get_data(node); */ if (!strcmp(type, "valid") || !strcmp(type, "invalid")) { /* got a reply, report it */ x = xode_new_tag("db:result"); xode_put_attrib(x, "xmlns:db", "jabber:server:dialback"); xode_put_attrib(x, "from", to); xode_put_attrib(x, "to", from); xode_put_attrib(x, "id", id); xode_put_attrib(x, "type", type); if (in_conn) xode_send(in_conn->fd, x); else LM_ERR("need to send reply to domain '%s', but no inbound" " connection found\n", from); xode_free(x); } } else if (!strcmp(tag, "db:result")) { char *type = xode_get_attrib(node, "type"); if (type && !strcmp(type, "valid")) { /* the remote server has successfully authenticated us, * we can now send data */ for (x = xode_get_firstchild(conn->todo); x; x = xode_get_nextsibling(x)) { LM_DBG("sending todo tag '%s'\n", xode_get_name(x)); xode_send(conn->fd, x); } xode_free(conn->todo); conn->todo = NULL; } } break; case XODE_STREAM_ERROR: LM_ERR("outstream error\n"); /* fall-through */ case XODE_STREAM_CLOSE: conn->type = CONN_DEAD; break; } xode_free(node); }
/** * authentication to the JABBER server */ int xj_jcon_user_auth(xj_jcon jbc, char *username, char *passwd, char *resource) { char msg_buff[4096]; int n, i, err; char *p0, *p1; xode x, y, z; /*** send open stream tag **/ sprintf(msg_buff, JB_CLIENT_OPEN_STREAM, jbc->hostname); if(send(jbc->sock, msg_buff, strlen(msg_buff), 0) != strlen(msg_buff)) goto error; n = recv(jbc->sock, msg_buff, 4096, 0); msg_buff[n] = 0; if(strncasecmp(msg_buff, JB_START_STREAM, JB_START_STREAM_LEN)) goto error; p0 = strstr(msg_buff + JB_START_STREAM_LEN, "id='"); if(p0 == NULL) goto error; p0 += 4; p1 = strchr(p0, '\''); if(p1 == NULL) goto error; jbc->stream_id = (char*)_M_MALLOC(p1-p0+1); strncpy(jbc->stream_id, p0, p1-p0); jbc->stream_id[p1-p0] = 0; sprintf(msg_buff, "%08X", jbc->seq_nr); x = xode_new_tag("iq"); if(!x) return -1; xode_put_attrib(x, "id", msg_buff); xode_put_attrib(x, "type", "get"); y = xode_insert_tag(x, "query"); xode_put_attrib(y, "xmlns", "jabber:iq:auth"); z = xode_insert_tag(y, "username"); xode_insert_cdata(z, username, -1); p0 = xode_to_str(x); n = strlen(p0); i = send(jbc->sock, p0, n, 0); if(i != n) goto errorx; xode_free(x); // receive response // try 10 times i = 10; while(i) { if((n = recv(jbc->sock, msg_buff, 4096, 0)) > 0) { msg_buff[n] = 0; break; } usleep(1000); i--; } if(!i) goto error; x = xode_from_strx(msg_buff, n, &err, &i); p0 = msg_buff; if(err) p0 += i; if(strncasecmp(xode_get_name(x), "iq", 2)) goto errorx; if((x = xode_get_tag(x, "query?xmlns=jabber:iq:auth")) == NULL) goto errorx; y = xode_new_tag("query"); xode_put_attrib(y, "xmlns", "jabber:iq:auth"); z = xode_insert_tag(y, "username"); xode_insert_cdata(z, username, -1); z = xode_insert_tag(y, "resource"); xode_insert_cdata(z, resource, -1); if(xode_get_tag(x, "digest") != NULL) { // digest authentication //sprintf(msg_buff, "%s%s", jbc->stream_id, passwd); strcpy(msg_buff, jbc->stream_id); strcat(msg_buff, passwd); //DBG("XJAB:xj_jcon_user_auth: [%s:%s]\n", jbc->stream_id, passwd); p1 = shahash(msg_buff); z = xode_insert_tag(y, "digest"); xode_insert_cdata(z, p1, -1); } else { // plaint text authentication z = xode_insert_tag(y, "password"); xode_insert_cdata(z, passwd, -1); } y = xode_wrap(y, "iq"); jbc->seq_nr++; sprintf(msg_buff, "%08X", jbc->seq_nr); xode_put_attrib(y, "id", msg_buff); xode_put_attrib(y, "type", "set"); p1 = xode_to_str(y); n = strlen(p1); i = send(jbc->sock, p1, n, 0); if(i != n) { xode_free(y); goto errorx; } xode_free(x); xode_free(y); // receive response // try 10 times i = 10; while(i) { if((n = recv(jbc->sock, msg_buff, 4096, 0)) > 0) { msg_buff[n] = 0; break; } usleep(1000); i--; } if(!i) goto error; x = xode_from_strx(msg_buff, n, &err, &i); p0 = msg_buff; if(err) p0 += i; if(strncasecmp(xode_get_name(x), "iq", 2) || strncasecmp(xode_get_attrib(x, "type"), "result", 6)) goto errorx; jbc->resource = (char*)_M_MALLOC(strlen(resource)+1); strcpy(jbc->resource, resource); jbc->allowed = XJ_NET_ALL; jbc->ready = XJ_NET_JAB; return 0; errorx: xode_free(x); error: return -1; }