Home | History | Annotate | Download | only in plus
      1 /*
      2  * libjingle
      3  * Copyright 2004--2005, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/base/stringencode.h"
     29 #include "presencepushtask.h"
     30 #include "talk/xmpp/constants.h"
     31 #include <sstream>
     32 
     33 
     34 namespace buzz {
     35 
     36 // string helper functions -----------------------------------------------------
     37 
     38 static bool
     39 IsXmlSpace(int ch) {
     40   return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
     41 }
     42 
     43 static bool
     44 ListContainsToken(const std::string & list, const std::string & token) {
     45   size_t i = list.find(token);
     46   if (i == std::string::npos || token.empty())
     47     return false;
     48   bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1]));
     49   bool boundary_after = (i == list.length() - token.length() || IsXmlSpace(list[i + token.length()]));
     50   return boundary_before && boundary_after;
     51 }
     52 
     53 
     54 bool
     55 PresencePushTask::HandleStanza(const XmlElement * stanza) {
     56   if (stanza->Name() != QN_PRESENCE)
     57     return false;
     58   if (stanza->HasAttr(QN_TYPE) && stanza->Attr(QN_TYPE) != STR_UNAVAILABLE) {
     59     if (stanza->Attr(QN_TYPE) == STR_ERROR) {
     60       // Pass on the error.
     61       const XmlElement* error_xml_elem = stanza->FirstNamed(QN_ERROR);
     62       if (!error_xml_elem) {
     63         return false;
     64       }
     65       SignalStatusError(*error_xml_elem);
     66       return true;
     67     }
     68   }
     69   QueueStanza(stanza);
     70   return true;
     71 }
     72 
     73 static bool IsUtf8FirstByte(int c) {
     74   return (((c)&0x80)==0) || // is single byte
     75     ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
     76 }
     77 
     78 int
     79 PresencePushTask::ProcessStart() {
     80   const XmlElement * stanza = NextStanza();
     81   if (stanza == NULL)
     82     return STATE_BLOCKED;
     83   Status s;
     84 
     85   s.set_jid(Jid(stanza->Attr(QN_FROM)));
     86 
     87   if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
     88     s.set_available(false);
     89     SignalStatusUpdate(s);
     90   }
     91   else {
     92     s.set_available(true);
     93     const XmlElement * status = stanza->FirstNamed(QN_STATUS);
     94     if (status != NULL) {
     95       s.set_status(status->BodyText());
     96 
     97       // Truncate status messages longer than 300 bytes
     98       if (s.status().length() > 300) {
     99         size_t len = 300;
    100 
    101         // Be careful not to split legal utf-8 chars in half
    102         while (!IsUtf8FirstByte(s.status()[len]) && len > 0) {
    103           len -= 1;
    104         }
    105         std::string truncated(s.status(), 0, len);
    106         s.set_status(truncated);
    107       }
    108     }
    109 
    110     const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
    111     if (priority != NULL) {
    112       int pri;
    113       if (talk_base::FromString(priority->BodyText(), &pri)) {
    114         s.set_priority(pri);
    115       }
    116     }
    117 
    118     const XmlElement * show = stanza->FirstNamed(QN_SHOW);
    119     if (show == NULL || show->FirstChild() == NULL) {
    120       s.set_show(Status::SHOW_ONLINE);
    121     }
    122     else {
    123       if (show->BodyText() == "away") {
    124         s.set_show(Status::SHOW_AWAY);
    125       }
    126       else if (show->BodyText() == "xa") {
    127         s.set_show(Status::SHOW_XA);
    128       }
    129       else if (show->BodyText() == "dnd") {
    130         s.set_show(Status::SHOW_DND);
    131       }
    132       else if (show->BodyText() == "chat") {
    133         s.set_show(Status::SHOW_CHAT);
    134       }
    135       else {
    136         s.set_show(Status::SHOW_ONLINE);
    137       }
    138     }
    139 
    140     const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
    141     if (caps != NULL) {
    142       std::string node = caps->Attr(QN_NODE);
    143       std::string ver = caps->Attr(QN_VER);
    144       std::string exts = caps->Attr(QN_EXT);
    145 
    146       s.set_know_capabilities(true);
    147       std::string capability;
    148       std::stringstream ss(exts);
    149       while (ss >> capability) {
    150         s.AddCapability(capability);
    151       }
    152 
    153       s->set_caps_node(node);
    154       s->set_version(ver);
    155     }
    156 
    157     const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
    158     if (delay != NULL) {
    159       // Ideally we would parse this according to the Psuedo ISO-8601 rules
    160       // that are laid out in JEP-0082:
    161       // http://www.jabber.org/jeps/jep-0082.html
    162       std::string stamp = delay->Attr(kQnStamp);
    163       s.set_sent_time(stamp);
    164     }
    165 
    166     const XmlElement *nick = stanza->FirstNamed(kQnNickname);
    167     if (nick) {
    168       std::string user_nick = nick->BodyText();
    169       s.set_user_nick(user_nick);
    170     }
    171 
    172     const XmlElement *plugin = stanza->FirstNamed(QN_PLUGIN);
    173     if (plugin) {
    174       const XmlElement *api_cap = plugin->FirstNamed(QN_CAPABILITY);
    175       if (api_cap) {
    176         const std::string &api_capability = api_cap->BodyText();
    177         s.set_api_capability(api_capability);
    178       }
    179       const XmlElement *api_msg = plugin->FirstNamed(QN_DATA);
    180       if (api_msg) {
    181         const std::string &api_message = api_msg->BodyText();
    182         s.set_api_message(api_message);
    183       }
    184     }
    185 
    186     const XmlElement* data_x = stanza->FirstNamed(QN_MUC_USER_X);
    187     if (data_x != NULL) {
    188       const XmlElement* item = data_x->FirstNamed(QN_MUC_USER_ITEM);
    189       if (item != NULL) {
    190         s.set_muc_role(item->Attr(QN_ROLE));
    191       }
    192     }
    193 
    194     SignalStatusUpdate(s);
    195   }
    196 
    197   return STATE_START;
    198 }
    199 
    200 
    201 }
    202