mcabber/src/jabglue.c
changeset 987 f47e312560af
parent 986 ed697234bd39
child 988 6e2bfd1ffded
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: