1 /*
2 * libjingle
3 * Copyright 2004--2012, 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/xmpp/presencereceivetask.h"
29
30 #include "talk/xmpp/constants.h"
31 #include "webrtc/base/stringencode.h"
32
33 namespace buzz {
34
IsUtf8FirstByte(int c)35 static bool IsUtf8FirstByte(int c) {
36 return (((c)&0x80)==0) || // is single byte
37 ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte
38 }
39
PresenceReceiveTask(XmppTaskParentInterface * parent)40 PresenceReceiveTask::PresenceReceiveTask(XmppTaskParentInterface* parent)
41 : XmppTask(parent, XmppEngine::HL_TYPE) {
42 }
43
~PresenceReceiveTask()44 PresenceReceiveTask::~PresenceReceiveTask() {
45 Stop();
46 }
47
ProcessStart()48 int PresenceReceiveTask::ProcessStart() {
49 const XmlElement * stanza = NextStanza();
50 if (stanza == NULL) {
51 return STATE_BLOCKED;
52 }
53
54 Jid from(stanza->Attr(QN_FROM));
55 HandlePresence(from, stanza);
56
57 return STATE_START;
58 }
59
HandleStanza(const XmlElement * stanza)60 bool PresenceReceiveTask::HandleStanza(const XmlElement * stanza) {
61 // Verify that this is a presence stanze
62 if (stanza->Name() != QN_PRESENCE) {
63 return false; // not sure if this ever happens.
64 }
65
66 // Queue it up
67 QueueStanza(stanza);
68
69 return true;
70 }
71
HandlePresence(const Jid & from,const XmlElement * stanza)72 void PresenceReceiveTask::HandlePresence(const Jid& from,
73 const XmlElement* stanza) {
74 if (stanza->Attr(QN_TYPE) == STR_ERROR) {
75 return;
76 }
77
78 PresenceStatus status;
79 DecodeStatus(from, stanza, &status);
80 PresenceUpdate(status);
81 }
82
DecodeStatus(const Jid & from,const XmlElement * stanza,PresenceStatus * presence_status)83 void PresenceReceiveTask::DecodeStatus(const Jid& from,
84 const XmlElement* stanza,
85 PresenceStatus* presence_status) {
86 presence_status->set_jid(from);
87 if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) {
88 presence_status->set_available(false);
89 } else {
90 presence_status->set_available(true);
91 const XmlElement * status_elem = stanza->FirstNamed(QN_STATUS);
92 if (status_elem != NULL) {
93 presence_status->set_status(status_elem->BodyText());
94
95 // Truncate status messages longer than 300 bytes
96 if (presence_status->status().length() > 300) {
97 size_t len = 300;
98
99 // Be careful not to split legal utf-8 chars in half
100 while (!IsUtf8FirstByte(presence_status->status()[len]) && len > 0) {
101 len -= 1;
102 }
103 std::string truncated(presence_status->status(), 0, len);
104 presence_status->set_status(truncated);
105 }
106 }
107
108 const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY);
109 if (priority != NULL) {
110 int pri;
111 if (rtc::FromString(priority->BodyText(), &pri)) {
112 presence_status->set_priority(pri);
113 }
114 }
115
116 const XmlElement * show = stanza->FirstNamed(QN_SHOW);
117 if (show == NULL || show->FirstChild() == NULL) {
118 presence_status->set_show(PresenceStatus::SHOW_ONLINE);
119 } else if (show->BodyText() == "away") {
120 presence_status->set_show(PresenceStatus::SHOW_AWAY);
121 } else if (show->BodyText() == "xa") {
122 presence_status->set_show(PresenceStatus::SHOW_XA);
123 } else if (show->BodyText() == "dnd") {
124 presence_status->set_show(PresenceStatus::SHOW_DND);
125 } else if (show->BodyText() == "chat") {
126 presence_status->set_show(PresenceStatus::SHOW_CHAT);
127 } else {
128 presence_status->set_show(PresenceStatus::SHOW_ONLINE);
129 }
130
131 const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C);
132 if (caps != NULL) {
133 std::string node = caps->Attr(QN_NODE);
134 std::string ver = caps->Attr(QN_VER);
135 std::string exts = caps->Attr(QN_EXT);
136
137 presence_status->set_know_capabilities(true);
138 presence_status->set_caps_node(node);
139 presence_status->set_version(ver);
140 }
141
142 const XmlElement* delay = stanza->FirstNamed(kQnDelayX);
143 if (delay != NULL) {
144 // Ideally we would parse this according to the Psuedo ISO-8601 rules
145 // that are laid out in JEP-0082:
146 // http://www.jabber.org/jeps/jep-0082.html
147 std::string stamp = delay->Attr(kQnStamp);
148 presence_status->set_sent_time(stamp);
149 }
150
151 const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME);
152 if (nick) {
153 presence_status->set_nick(nick->BodyText());
154 }
155 }
156 }
157
158 } // namespace buzz
159