comparison mcabber/src/jabglue.c @ 987:f47e312560af

Improve JEP22 + JEP85 support
author Mikael Berthe <mikael@lilotux.net>
date Mon, 30 Oct 2006 20:18:00 +0100
parents ed697234bd39
children 6e2bfd1ffded
comparison
equal deleted inserted replaced
986:ed697234bd39 987:f47e312560af
414 void jb_send_msg(const char *jid, const char *text, int type, 414 void jb_send_msg(const char *jid, const char *text, int type,
415 const char *subject) 415 const char *subject)
416 { 416 {
417 xmlnode x; 417 xmlnode x;
418 gchar *strtype; 418 gchar *strtype;
419 #if defined JEP0022 || defined JEP0085
420 xmlnode event;
421 char *rname, *barejid;
422 GSList *sl_buddy;
423 guint which_jep = 0; /* 0: none, 1: 85, 2: 22 */
424 struct jep0085 *jep85 = NULL;
425 #endif
419 426
420 if (!online) return; 427 if (!online) return;
421 428
422 if (type == ROSTER_TYPE_ROOM) 429 if (type == ROSTER_TYPE_ROOM)
423 strtype = TMSG_GROUPCHAT; 430 strtype = TMSG_GROUPCHAT;
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();
1037 xmlnode x; 1073 xmlnode x;
1038 char *p; 1074 char *p;
1039 1075
1040 x = xmlnode_get_firstchild(xmldata); 1076 x = xmlnode_get_firstchild(xmldata);
1041 for ( ; x; x = xmlnode_get_nextsibling(x)) { 1077 for ( ; x; x = xmlnode_get_nextsibling(x)) {
1042 if ((p = xmlnode_get_name(x)) && !strcmp(p, "x")) 1078 if ((p = xmlnode_get_attrib(x, "xmlns")) && !strcmp(p, xmlns))
1043 if ((p = xmlnode_get_attrib(x, "xmlns")) && !strcmp(p, xmlns)) { 1079 break;
1044 break;
1045 }
1046 } 1080 }
1047 return x; 1081 return x;
1048 } 1082 }
1049 1083
1050 static time_t xml_get_timestamp(xmlnode xmldata) 1084 static time_t xml_get_timestamp(xmlnode xmldata)
1390 static void handle_packet_message(jconn conn, char *type, char *from, 1424 static void handle_packet_message(jconn conn, char *type, char *from,
1391 xmlnode xmldata) 1425 xmlnode xmldata)
1392 { 1426 {
1393 char *p, *r, *s; 1427 char *p, *r, *s;
1394 xmlnode x; 1428 xmlnode x;
1395 char *body=NULL; 1429 char *body = NULL;
1396 char *enc = NULL; 1430 char *enc = NULL;
1397 char *tmp = NULL; 1431 char *tmp = NULL;
1398 time_t timestamp = 0; 1432 time_t timestamp = 0;
1399 1433
1400 body = xmlnode_get_tag_data(xmldata, "body"); 1434 body = xmlnode_get_tag_data(xmldata, "body");
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;
1641 } 1736 }
1642 1737
1643 static void packethandler(jconn conn, jpacket packet) 1738 static void packethandler(jconn conn, jpacket packet)
1644 { 1739 {
1645 char *p; 1740 char *p;
1646 /*
1647 char *r, *s;
1648 const char *m;
1649 */
1650 char *from=NULL, *type=NULL; 1741 char *from=NULL, *type=NULL;
1651 1742
1652 jb_reset_keepalive(); // reset keepalive timeout 1743 jb_reset_keepalive(); // reset keepalive timeout
1653 jpacket_reset(packet); 1744 jpacket_reset(packet);
1654 1745
1662 1753
1663 p = xmlnode_get_attrib(packet->x, "from"); 1754 p = xmlnode_get_attrib(packet->x, "from");
1664 if (p) from = p; 1755 if (p) from = p;
1665 1756
1666 if (!from && packet->type != JPACKET_IQ) { 1757 if (!from && packet->type != JPACKET_IQ) {
1667 scr_LogPrint(LPRINT_LOGNORM, "Error in packet (could be UTF8-related)"); 1758 scr_LogPrint(LPRINT_LOGNORM, "Error in stream packet");
1668 return; 1759 return;
1669 } 1760 }
1670 1761
1671 switch (packet->type) { 1762 switch (packet->type) {
1672 case JPACKET_MESSAGE: 1763 case JPACKET_MESSAGE: