/** * parse incoming message from Jabber server */ int xj_manage_jab(char *buf, int len, int *pos, xj_jalias als, xj_jcon jbc) { int j, err=0; char *p, *to, *from, *msg, *type, *emsg, *ecode, lbuf[4096], fbuf[128]; xj_jconf jcf = NULL; str ts, tf; xode x, y, z; str *sid; xj_pres_cell prc = NULL; if(!jbc) return -1; sid = jbc->jkey->id; x = xode_from_strx(buf, len, &err, &j); #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_parse_jab: XODE ret:%d pos:%d\n", err, j); #endif if(err && pos != NULL) *pos= j; if(x == NULL) return -1; lbuf[0] = 0; ecode = NULL; /******************** XMPP 'MESSAGE' HANDLING **********************/ if(!strncasecmp(xode_get_name(x), "message", 7)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: jabber [message] received\n"); #endif if((to = xode_get_attrib(x, "to")) == NULL) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: missing 'to' attribute\n"); #endif err = -1; goto ready; } if((from = xode_get_attrib(x, "from")) == NULL) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: missing 'from' attribute\n"); #endif err = -1; goto ready; } if((y = xode_get_tag(x, "body")) == NULL || (msg = xode_get_data(y)) == NULL) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: missing 'body' of message\n"); #endif err = -1; goto ready; } type = xode_get_attrib(x, "type"); if(type != NULL && !strncasecmp(type, "error", 5)) { if((y = xode_get_tag(x, "error")) == NULL || (emsg = xode_get_data(y)) == NULL) strcpy(lbuf, "{Error sending following message} - "); else { ecode = xode_get_attrib(y, "code"); strcpy(lbuf, "{Error ("); if(ecode != NULL) { strcat(lbuf, ecode); strcat(lbuf, " - "); } strcat(lbuf, emsg); strcat(lbuf, ") when trying to send following message}"); } } // is from a conference?!?! if((jcf=xj_jcon_check_jconf(jbc, from))!=NULL) { if(lbuf[0] == 0) { p = from + strlen(from); while(p>from && *p != '/') p--; if(*p == '/') { if(jcf->nick.len>0 && strlen(p+1) == jcf->nick.len && !strncasecmp(p+1, jcf->nick.s, jcf->nick.len)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: message sent by myself\n"); #endif goto ready; } lbuf[0] = '['; lbuf[1] = 0; strcat(lbuf, p+1); strcat(lbuf, "] "); } } else { jcf->status = XJ_JCONF_NULL; xj_jcon_jconf_presence(jbc,jcf,NULL,"online"); } strcat(lbuf, msg); ts.s = lbuf; ts.len = strlen(lbuf); if(xj_send_sip_msg(als->proxy, sid, &jcf->uri, &ts, &jbc->jkey->flag)<0) DBG("XJAB:xj_manage_jab: ERROR SIP MESSAGE was not sent!\n"); #ifdef XJ_EXTRA_DEBUG else DBG("XJAB:xj_manage_jab: SIP MESSAGE was sent!\n"); #endif goto ready; } strcat(lbuf, msg); ts.s = from; ts.len = strlen(from); tf.s = fbuf; tf.len = 0; if(xj_address_translation(&ts, &tf, als, XJ_ADDRTR_J2S) == 0) { ts.s = lbuf; ts.len = strlen(lbuf); if(xj_send_sip_msg(als->proxy, sid, &tf, &ts, &jbc->jkey->flag)<0) DBG("XJAB:xj_manage_jab: ERROR SIP MESSAGE was not sent ...\n"); #ifdef XJ_EXTRA_DEBUG else DBG("XJAB:xj_manage_jab: SIP MESSAGE was sent.\n"); #endif } goto ready; } /*------------------- END 'MESSAGE' HANDLING ----------------------*/ /******************** XMPP 'PRESENCE' HANDLING *********************/ if(!strncasecmp(xode_get_name(x), "presence", 8)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: jabber [presence] received\n"); #endif type = xode_get_attrib(x, "type"); from = xode_get_attrib(x, "from"); if(from == NULL) goto ready; ts.s = from; p = from; while(p<from + strlen(from) && *p != '/') p++; if(*p == '/') ts.len = p - from; else ts.len = strlen(from); if(type == NULL || !strncasecmp(type, "online", 6) || !strncasecmp(type, "available", 9)) { if(strchr(from, '@') == NULL) { if(!strncasecmp(from, XJ_AIM_NAME, XJ_AIM_LEN)) { jbc->ready |= XJ_NET_AIM; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: AIM network ready\n"); #endif } else if(!strncasecmp(from, XJ_ICQ_NAME, XJ_ICQ_LEN)) { jbc->ready |= XJ_NET_ICQ; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: ICQ network ready\n"); #endif } else if(!strncasecmp(from, XJ_MSN_NAME, XJ_MSN_LEN)) { jbc->ready |= XJ_NET_MSN; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: MSN network ready\n"); #endif } else if(!strncasecmp(from, XJ_YAH_NAME, XJ_YAH_LEN)) { jbc->ready |= XJ_NET_YAH; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: YAHOO network ready\n"); #endif } } else if((jcf=xj_jcon_check_jconf(jbc, from))!=NULL) { jcf->status = XJ_JCONF_READY; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: %s conference ready\n", from); #endif } else { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: user <%.*s> is online\n",ts.len,ts.s); #endif prc = xj_pres_list_check(jbc->plist, &ts); if(prc) { if(prc->state != XJ_PS_ONLINE) { prc->state = XJ_PS_ONLINE; goto call_pa_cbf; } } else { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: user state received - creating" " presence cell for [%.*s]\n", ts.len, ts.s); #endif prc = xj_pres_cell_new(); if(prc == NULL) { DBG("XJAB:xj_manage_jab: cannot create presence" " cell for [%s]\n", from); goto ready; } if(xj_pres_cell_init(prc, &ts, NULL, NULL)<0) { DBG("XJAB:xj_manage_jab: cannot init presence" " cell for [%s]\n", from); xj_pres_cell_free(prc); goto ready; } prc = xj_pres_list_add(jbc->plist, prc); if(prc) { prc->state = XJ_PS_ONLINE; goto call_pa_cbf; } } } goto ready; } if(strchr(from, '@') == NULL) goto ready; if(!strncasecmp(type, "error", 5)) { if((jcf=xj_jcon_check_jconf(jbc, from))!=NULL) { tf.s = from; tf.len = strlen(from); if((y = xode_get_tag(x, "error")) == NULL) goto ready; if ((p = xode_get_attrib(y, "code")) != NULL && atoi(p) == 409) { xj_send_sip_msgz(als->proxy, sid, &tf, XJ_DMSG_ERR_JCONFNICK, &jbc->jkey->flag); goto ready; } xj_send_sip_msgz(als->proxy,sid,&tf,XJ_DMSG_ERR_JCONFREFUSED, &jbc->jkey->flag); } goto ready; } if(type!=NULL && !strncasecmp(type, "subscribe", 9)) { xj_jcon_send_presence(jbc, from, "subscribed", NULL, NULL); goto ready; } prc = xj_pres_list_check(jbc->plist, &ts); if(!prc) goto ready; if(!strncasecmp(type, "unavailable", 11)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: user <%s> is offline\n", from); #endif if(prc->state != XJ_PS_OFFLINE) { prc->state = XJ_PS_OFFLINE; goto call_pa_cbf; } goto ready; } if(!strncasecmp(type, "unsubscribed", 12)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: user <%s> does not allow to see his" " presence status\n", from); #endif if(prc->state != XJ_PS_REFUSED) { prc->state = XJ_PS_REFUSED; goto call_pa_cbf; } } // ignoring unknown types goto ready; } /*------------------- END XMPP 'PRESENCE' HANDLING ----------------*/ /******************** XMPP 'IQ' HANDLING ***************************/ if(!strncasecmp(xode_get_name(x), "iq", 2)) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: jabber [iq] received\n"); #endif if(!strncasecmp(xode_get_attrib(x, "type"), "result", 6)) { if((y = xode_get_tag(x, "query?xmlns=jabber:iq:roster")) == NULL) goto ready; z = xode_get_firstchild(y); while(z) { if(!strncasecmp(xode_get_name(z), "item", 5) && (from = xode_get_attrib(z, "jid")) != NULL) { if(strchr(from, '@') == NULL) { // transports if(!strncasecmp(from, XJ_AIM_NAME, XJ_AIM_LEN)) { jbc->allowed |= XJ_NET_AIM; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab:AIM network available\n"); #endif } else if(!strncasecmp(from, XJ_ICQ_NAME, XJ_ICQ_LEN)) { jbc->allowed |= XJ_NET_ICQ; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab:ICQ network available\n"); #endif } else if(!strncasecmp(from, XJ_MSN_NAME, XJ_MSN_LEN)) { jbc->allowed |= XJ_NET_MSN; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab:MSN network available\n"); #endif } else if(!strncasecmp(from, XJ_YAH_NAME, XJ_YAH_LEN)) { jbc->allowed |= XJ_NET_YAH; #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab:YAHOO network available\n"); #endif } goto next_sibling; } } next_sibling: z = xode_get_nextsibling(z); } } goto ready; } /*------------------- END XMPP 'IQ' HANDLING ----------------------*/ call_pa_cbf: if(prc && prc->cbf) { // call the PA callback function tf.s = fbuf; tf.len = 0; if(xj_address_translation(&ts,&tf,als,XJ_ADDRTR_J2S)==0) { #ifdef XJ_EXTRA_DEBUG DBG("XJAB:xj_manage_jab: calling CBF(%.*s,%d)\n", tf.len, tf.s, prc->state); #endif (*(prc->cbf))(&tf, &tf, prc->state, prc->cbp); } } ready: xode_free(x); return err; }
/** * 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; }