429 xmlnode y; |
436 xmlnode y; |
430 y = xmlnode_insert_tag(x, "subject"); |
437 y = xmlnode_insert_tag(x, "subject"); |
431 xmlnode_insert_cdata(y, subject, (unsigned) -1); |
438 xmlnode_insert_cdata(y, subject, (unsigned) -1); |
432 } |
439 } |
433 |
440 |
434 // TODO: insert event notifications request |
441 #if defined JEP0022 || defined JEP0085 |
435 #undef USE_JEP_85 |
442 rname = strchr(jid, JID_RESOURCE_SEPARATOR); |
436 #ifdef USE_JEP_85 |
443 barejid = jidtodisp(jid); |
437 #define NS_CHAT_STATES "http://jabber.org/features/chatstates" |
444 sl_buddy = roster_find(barejid, jidsearch, ROSTER_TYPE_USER); |
438 // JEP-85 |
445 g_free(barejid); |
439 xmlnode event = xmlnode_insert_tag(x, "composing"); |
446 |
440 xmlnode_put_attrib(event, "xmlns", NS_CHAT_STATES); |
447 // If we can get a resource name, we use it. Else we use NULL, |
441 #else |
448 // which hopefully will give us the most likely resource. |
442 // JEP-22 |
449 if (rname) |
443 xmlnode event = xmlnode_insert_tag(x, "x"); |
450 rname++; |
444 xmlnode_put_attrib(event, "xmlns", NS_EVENT); |
451 if (sl_buddy) |
445 xmlnode_insert_tag(event, "composing"); |
452 jep85 = buddy_resource_jep85(sl_buddy->data, rname); |
446 #endif |
453 #endif |
447 |
454 |
|
455 #ifdef JEP0085 |
|
456 /* JEP-0085 5.1 |
|
457 * "Until receiving a reply to the initial content message (or a standalone |
|
458 * notification) from the Contact, the User MUST NOT send subsequent chat |
|
459 * state notifications to the Contact." |
|
460 * In our implementation support is initially "unknown", they it's "probed" |
|
461 * and can become "ok". |
|
462 */ |
|
463 if (jep85 && (jep85->support == CHATSTATES_SUPPORT_OK || |
|
464 jep85->support == CHATSTATES_SUPPORT_UNKNOWN)) { |
|
465 event = xmlnode_insert_tag(x, "active"); |
|
466 xmlnode_put_attrib(event, "xmlns", NS_CHATSTATES); |
|
467 if (jep85->support == CHATSTATES_SUPPORT_UNKNOWN) |
|
468 jep85->support = CHATSTATES_SUPPORT_PROBED; |
|
469 else |
|
470 which_jep = 1; |
|
471 } |
|
472 #endif |
|
473 #ifdef JEP0022 |
|
474 /* JEP-22 |
|
475 * If the Contact supports JEP-0085, we do not use JEP-0022. |
|
476 * If not, we try to fall back to JEP-0022. |
|
477 */ |
|
478 if (!which_jep) { |
|
479 event = xmlnode_insert_tag(x, "x"); |
|
480 xmlnode_put_attrib(event, "xmlns", NS_EVENT); |
|
481 xmlnode_insert_tag(event, "composing"); |
|
482 } |
|
483 #endif |
448 |
484 |
449 jab_send(jc, x); |
485 jab_send(jc, x); |
450 xmlnode_free(x); |
486 xmlnode_free(x); |
451 |
487 |
452 jb_reset_keepalive(); |
488 jb_reset_keepalive(); |
1457 if (from && body) |
1491 if (from && body) |
1458 gotmessage(type, from, body, enc, timestamp); |
1492 gotmessage(type, from, body, enc, timestamp); |
1459 g_free(tmp); |
1493 g_free(tmp); |
1460 } |
1494 } |
1461 |
1495 |
1462 void handle_state_events(char* from, xmlnode xmldata) |
1496 void handle_state_events(char *from, xmlnode xmldata) |
1463 { |
1497 { |
1464 xmlnode x = NULL; |
1498 #if defined JEP0022 || defined JEP0085 |
1465 char *rname = strchr(from, JID_RESOURCE_SEPARATOR) + 1; |
1499 xmlnode state_ns; |
1466 char *jid = jidtodisp(from); |
1500 const char *body; |
1467 GSList *slist = roster_find(jid, jidsearch, ROSTER_TYPE_USER); |
1501 char *rname, *jid; |
1468 if (slist == NULL) return; |
1502 GSList *sl_buddy; |
1469 int jep85 = 0; |
1503 guint events; |
1470 |
1504 guint which_jep = 0; /* 0: none, 1: 85, 2: 22 */ |
1471 guint events = buddy_resource_getevents(slist->data, rname); |
1505 struct jep0022 *jep22; |
1472 |
1506 struct jep0085 *jep85; |
1473 x = xml_get_xmlns(xmldata, NS_EVENT); |
1507 |
1474 if (x == NULL) { |
1508 rname = strchr(from, JID_RESOURCE_SEPARATOR); |
1475 x = xmldata; |
1509 jid = jidtodisp(from); |
1476 jep85 = 1; |
1510 sl_buddy = roster_find(jid, jidsearch, ROSTER_TYPE_USER); |
1477 } |
1511 |
1478 |
1512 /* XXX Actually that's wrong, since it filters out server "offline" |
1479 xmlnode tag = xmlnode_get_tag(x, "composing"); |
1513 messages (for JEP-0022) */ |
1480 if (tag != NULL) { |
1514 if (!sl_buddy || !rname++) { |
1481 events |= ROSTER_EVENT_COMPOSING; |
1515 g_free(jid); |
1482 } else if (!jep85) { |
1516 return; |
1483 events &= ~ROSTER_EVENT_COMPOSING; |
1517 } |
1484 } |
1518 |
1485 |
1519 events = buddy_resource_getevents(sl_buddy->data, rname); |
|
1520 |
|
1521 jep85 = buddy_resource_jep85(sl_buddy->data, rname); |
1486 if (jep85) { |
1522 if (jep85) { |
1487 tag = xmlnode_get_tag(x, "paused"); |
1523 state_ns = xml_get_xmlns(xmldata, NS_CHATSTATES); |
1488 if (tag != NULL) { |
1524 if (state_ns) |
|
1525 which_jep = 1; |
|
1526 } |
|
1527 |
|
1528 if (which_jep != 1) { /* Fall back to JEP-0022 */ |
|
1529 jep22 = buddy_resource_jep22(sl_buddy->data, rname); |
|
1530 if (jep22) { |
|
1531 state_ns = xml_get_xmlns(xmldata, NS_EVENT); |
|
1532 if (state_ns) |
|
1533 which_jep = 2; |
|
1534 } |
|
1535 } |
|
1536 |
|
1537 if (!which_jep) { /* Sender does not use chat states */ |
|
1538 g_free(jid); |
|
1539 return; |
|
1540 } |
|
1541 |
|
1542 body = xmlnode_get_tag_data(xmldata, "body"); |
|
1543 |
|
1544 if (which_jep == 1) { /* JEP-0085 */ |
|
1545 const char *p; |
|
1546 jep85->support = CHATSTATES_SUPPORT_OK; |
|
1547 |
|
1548 p = xmlnode_get_name(state_ns); |
|
1549 if (!strcmp(p, "composing")) { |
|
1550 jep85->last_state_rcvd = ROSTER_EVENT_COMPOSING; |
|
1551 } else if (!strcmp(p, "active")) { |
|
1552 jep85->last_state_rcvd = ROSTER_EVENT_ACTIVE; |
|
1553 } else if (!strcmp(p, "paused")) { |
|
1554 jep85->last_state_rcvd = ROSTER_EVENT_PAUSED; |
|
1555 } else if (!strcmp(p, "inactive")) { |
|
1556 jep85->last_state_rcvd = ROSTER_EVENT_INACTIVE; |
|
1557 } else if (!strcmp(p, "gone")) { |
|
1558 jep85->last_state_rcvd = ROSTER_EVENT_GONE; |
|
1559 } |
|
1560 |
|
1561 if (jep85->last_state_rcvd == ROSTER_EVENT_COMPOSING) |
|
1562 events = ROSTER_EVENT_COMPOSING; |
|
1563 else |
|
1564 events = ROSTER_EVENT_NONE; |
|
1565 } else { /* JEP-0022 */ |
|
1566 const char *msgid; |
|
1567 jep22->support = CHATSTATES_SUPPORT_OK; |
|
1568 jep22->last_state_rcvd = ROSTER_EVENT_NONE; |
|
1569 |
|
1570 msgid = xmlnode_get_attrib(xmldata, "id"); |
|
1571 |
|
1572 if (xmlnode_get_tag(state_ns, "composing")) { |
|
1573 // Clear composing if the message contains a body |
|
1574 if (body) |
1489 events &= ~ROSTER_EVENT_COMPOSING; |
1575 events &= ~ROSTER_EVENT_COMPOSING; |
1490 } |
1576 else |
1491 } |
1577 events |= ROSTER_EVENT_COMPOSING; |
1492 |
1578 jep22->last_state_rcvd |= ROSTER_EVENT_COMPOSING; |
1493 // clear composing and set new message event |
1579 |
1494 // if message contains message body |
1580 } else { |
1495 if (xmlnode_get_tag_data(xmldata, "body") != NULL) { |
1581 events &= ~ROSTER_EVENT_COMPOSING; |
1496 events |= ROSTER_EVENT_MSG; |
1582 } |
1497 events &= ~ROSTER_EVENT_COMPOSING; |
1583 |
1498 } |
1584 if (xmlnode_get_tag(state_ns, "delivered")) |
1499 |
1585 jep22->last_state_rcvd |= ROSTER_EVENT_DELIVERED; |
1500 buddy_resource_setevents(slist->data, rname, events); |
1586 |
1501 |
1587 // Cache the message id |
1502 scr_UpdateBuddyWindow(); |
1588 g_free(jep22->last_msgid_rcvd); |
1503 scr_DrawRoster(); |
1589 if (msgid) |
|
1590 jep22->last_msgid_rcvd = g_strdup(msgid); |
|
1591 else |
|
1592 jep22->last_msgid_rcvd = NULL; |
|
1593 } |
|
1594 |
|
1595 buddy_resource_setevents(sl_buddy->data, rname, events); |
|
1596 |
|
1597 update_roster = TRUE; |
1504 |
1598 |
1505 g_free(jid); |
1599 g_free(jid); |
|
1600 #endif |
1506 } |
1601 } |
1507 |
1602 |
1508 static void evscallback_subscription(eviqs *evp, guint evcontext) |
1603 static void evscallback_subscription(eviqs *evp, guint evcontext) |
1509 { |
1604 { |
1510 char *barejid; |
1605 char *barejid; |