1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2010, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <stdio.h>
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <string>
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/sessionmessages.h"
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "talk/base/logging.h"
33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "talk/base/scoped_ptr.h"
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "talk/base/stringutils.h"
354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/xmllite/xmlconstants.h"
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/constants.h"
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/constants.h"
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/p2ptransport.h"
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/parsing.h"
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/sessionclient.h"
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "talk/p2p/base/sessiondescription.h"
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/transport.h"
43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "talk/xmllite/xmlconstants.h"
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace cricket {
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochActionType ToActionType(const std::string& type) {
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_INITIATE)
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_SESSION_INITIATE;
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_INFO)
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_SESSION_INFO;
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_ACCEPT)
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_SESSION_ACCEPT;
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_REJECT)
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_SESSION_REJECT;
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_TERMINATE)
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_SESSION_TERMINATE;
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == GINGLE_ACTION_CANDIDATES)
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_TRANSPORT_INFO;
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_SESSION_INITIATE)
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_SESSION_INITIATE;
62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_TRANSPORT_INFO)
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_TRANSPORT_INFO;
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_TRANSPORT_ACCEPT;
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_SESSION_INFO)
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_SESSION_INFO;
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_SESSION_ACCEPT)
69731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_SESSION_ACCEPT;
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (type == JINGLE_ACTION_SESSION_TERMINATE)
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ACTION_SESSION_TERMINATE;
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (type == JINGLE_ACTION_TRANSPORT_INFO)
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return ACTION_TRANSPORT_INFO;
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (type == JINGLE_ACTION_TRANSPORT_ACCEPT)
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ACTION_TRANSPORT_ACCEPT;
76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (type == GINGLE_ACTION_NOTIFY)
77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return ACTION_NOTIFY;
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (type == GINGLE_ACTION_UPDATE)
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return ACTION_UPDATE;
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return ACTION_UNKNOWN;
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string ToJingleString(ActionType type) {
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  switch (type) {
86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_SESSION_INITIATE:
87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_SESSION_INITIATE;
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_SESSION_INFO:
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_SESSION_INFO;
90731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_SESSION_ACCEPT:
91731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_SESSION_ACCEPT;
92731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Notice that reject and terminate both go to
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // "session-terminate", but there is no "session-reject".
94731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_SESSION_REJECT:
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_SESSION_TERMINATE:
96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_SESSION_TERMINATE;
97731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_TRANSPORT_INFO:
98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_TRANSPORT_INFO;
99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    case ACTION_TRANSPORT_ACCEPT:
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return JINGLE_ACTION_TRANSPORT_ACCEPT;
101731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    default:
102731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return "";
103731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string ToGingleString(ActionType type) {
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (type) {
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_SESSION_INITIATE:
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return GINGLE_ACTION_INITIATE;
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_SESSION_INFO:
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return GINGLE_ACTION_INFO;
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_SESSION_ACCEPT:
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return GINGLE_ACTION_ACCEPT;
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_SESSION_REJECT:
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return GINGLE_ACTION_REJECT;
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_SESSION_TERMINATE:
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return GINGLE_ACTION_TERMINATE;
118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    case ACTION_VIEW:
119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return GINGLE_ACTION_VIEW;
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    case ACTION_TRANSPORT_INFO:
121731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return GINGLE_ACTION_CANDIDATES;
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    default:
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return "";
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
128731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool IsJingleMessage(const buzz::XmlElement* stanza) {
129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE);
130731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (jingle == NULL)
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (jingle->HasAttr(buzz::QN_ACTION) &&
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          (jingle->HasAttr(QN_SID)
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           // TODO: This works around a bug in old jingle
136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           // clients that set QN_ID instead of QN_SID.  Once we know
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           // there are no clients which have this bug, we can remove
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           // this code.
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           || jingle->HasAttr(QN_ID)));
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
142731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool IsGingleMessage(const buzz::XmlElement* stanza) {
143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION);
144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (session == NULL)
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (session->HasAttr(buzz::QN_TYPE) &&
148731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          session->HasAttr(buzz::QN_ID)   &&
149731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          session->HasAttr(QN_INITIATOR));
150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool IsSessionMessage(const buzz::XmlElement* stanza) {
153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (stanza->Name() == buzz::QN_IQ &&
154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          stanza->Attr(buzz::QN_TYPE) == buzz::STR_SET &&
155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          (IsJingleMessage(stanza) ||
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           IsGingleMessage(stanza)));
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
159731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleSessionMessage(const buzz::XmlElement* session,
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               SessionMessage* msg,
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               ParseError* error) {
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->protocol = PROTOCOL_GINGLE;
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string type_string = session->Attr(buzz::QN_TYPE);
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->type = ToActionType(type_string);
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->sid = session->Attr(buzz::QN_ID);
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->initiator = session->Attr(QN_INITIATOR);
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->action_elem = session;
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (msg->type == ACTION_UNKNOWN)
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return BadParse("unknown action: " + type_string, error);
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleSessionMessage(const buzz::XmlElement* jingle,
176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               SessionMessage* msg,
177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               ParseError* error) {
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->protocol = PROTOCOL_JINGLE;
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string type_string = jingle->Attr(buzz::QN_ACTION);
180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->type = ToActionType(type_string);
181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  msg->sid = jingle->Attr(QN_SID);
182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO: This works around a bug in old jingle clients
183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // that set QN_ID instead of QN_SID.  Once we know there are no
184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // clients which have this bug, we can remove this code.
185dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (msg->sid.empty()) {
186dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    msg->sid = jingle->Attr(buzz::QN_ID);
187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
1884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY);
189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->action_elem = jingle;
190731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (msg->type == ACTION_UNKNOWN)
192731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return BadParse("unknown action: " + type_string, error);
193731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
195731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
197731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseHybridSessionMessage(const buzz::XmlElement* jingle,
198731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               SessionMessage* msg,
199731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               ParseError* error) {
200731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!ParseJingleSessionMessage(jingle, msg, error))
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  msg->protocol = PROTOCOL_HYBRID;
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
205731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
207731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseSessionMessage(const buzz::XmlElement* stanza,
208731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         SessionMessage* msg,
209731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         ParseError* error) {
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg->id = stanza->Attr(buzz::QN_ID);
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg->from = stanza->Attr(buzz::QN_FROM);
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg->to = stanza->Attr(buzz::QN_TO);
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  msg->stanza = stanza;
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE);
216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION);
217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (jingle && session)
218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ParseHybridSessionMessage(jingle, msg, error);
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (jingle != NULL)
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ParseJingleSessionMessage(jingle, msg, error);
221731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (session != NULL)
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ParseGingleSessionMessage(session, msg, error);
223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return false;
224731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
226731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* WriteGingleAction(const SessionMessage& msg,
227731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                    const XmlElements& action_elems) {
228731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* session = new buzz::XmlElement(QN_GINGLE_SESSION, true);
229731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  session->AddAttr(buzz::QN_TYPE, ToGingleString(msg.type));
230731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  session->AddAttr(buzz::QN_ID, msg.sid);
231731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  session->AddAttr(QN_INITIATOR, msg.initiator);
232731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlChildren(session, action_elems);
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return session;
234731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
236731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* WriteJingleAction(const SessionMessage& msg,
237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                    const XmlElements& action_elems) {
238731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true);
239731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type));
240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  jingle->AddAttr(QN_SID, msg.sid);
241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO: This works around a bug in old jingle clinets
242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // that expected QN_ID instead of QN_SID.  Once we know there are no
243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // clients which have this bug, we can remove this code.
244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  jingle->AddAttr(QN_ID, msg.sid);
245731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: Right now, the XMPP server rejects a jingle-only
246731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // (non hybrid) message with "feature-not-implemented" if there is
247731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // no initiator.  Fix the server, and then only set the initiator on
248731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // session-initiate messages here.
249731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  jingle->AddAttr(QN_INITIATOR, msg.initiator);
250731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlChildren(jingle, action_elems);
251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return jingle;
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid WriteSessionMessage(const SessionMessage& msg,
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         const XmlElements& action_elems,
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         buzz::XmlElement* stanza) {
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  stanza->SetAttr(buzz::QN_TO, msg.to);
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  stanza->SetAttr(buzz::QN_TYPE, buzz::STR_SET);
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
260731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (msg.protocol == PROTOCOL_GINGLE) {
261731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    stanza->AddElement(WriteGingleAction(msg, action_elems));
262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
263731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    stanza->AddElement(WriteJingleAction(msg, action_elems));
264731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochTransportParser* GetTransportParser(const TransportParserMap& trans_parsers,
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                    const std::string& name) {
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  TransportParserMap::const_iterator map = trans_parsers.find(name);
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (map == trans_parsers.end()) {
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return NULL;
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return map->second;
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseCandidates(SignalingProtocol protocol,
279731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const buzz::XmlElement* candidates_elem,
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                     const TransportParserMap& trans_parsers,
281731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const std::string& transport_type,
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                     Candidates* candidates,
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                     ParseError* error) {
284731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportParser* trans_parser =
285731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      GetTransportParser(trans_parsers, transport_type);
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (trans_parser == NULL)
287731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return BadParse("unknown transport type: " + transport_type, error);
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
289731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return trans_parser->ParseCandidates(protocol, candidates_elem,
290731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                       candidates, error);
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
293731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleTransportInfos(const buzz::XmlElement* action_elem,
294731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const ContentInfos& contents,
295731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const TransportParserMap& trans_parsers,
296731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               TransportInfos* tinfos,
297731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               ParseError* error) {
298731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportInfo tinfo(CN_OTHER, NS_GINGLE_P2P, Candidates());
299731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!ParseCandidates(PROTOCOL_GINGLE, action_elem,
300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       trans_parsers, NS_GINGLE_P2P,
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       &tinfo.candidates, error))
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool has_audio = FindContentInfoByName(contents, CN_AUDIO) != NULL;
305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool has_video = FindContentInfoByName(contents, CN_VIDEO) != NULL;
306731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
307731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If we don't have media, no need to separate the candidates.
308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!has_audio && !has_audio) {
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    tinfos->push_back(tinfo);
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return true;
311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If we have media, separate the candidates.  Create the
314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TransportInfo here to avoid copying the candidates.
315731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportInfo audio_tinfo(CN_AUDIO, NS_GINGLE_P2P, Candidates());
316731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportInfo video_tinfo(CN_VIDEO, NS_GINGLE_P2P, Candidates());
317731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (Candidates::iterator cand = tinfo.candidates.begin();
318731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       cand != tinfo.candidates.end(); cand++) {
319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (cand->name() == GINGLE_CANDIDATE_NAME_RTP ||
320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        cand->name() == GINGLE_CANDIDATE_NAME_RTCP) {
321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      audio_tinfo.candidates.push_back(*cand);
322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else if (cand->name() == GINGLE_CANDIDATE_NAME_VIDEO_RTP ||
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick               cand->name() == GINGLE_CANDIDATE_NAME_VIDEO_RTCP) {
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      video_tinfo.candidates.push_back(*cand);
325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
328731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (has_audio) {
329731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    tinfos->push_back(audio_tinfo);
330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
331731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
332731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (has_video) {
333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    tinfos->push_back(video_tinfo);
334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
335731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
339731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleTransportInfo(const buzz::XmlElement* trans_elem,
340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              const ContentInfo& content,
341731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              const TransportParserMap& trans_parsers,
342731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              TransportInfos* tinfos,
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                              ParseError* error) {
344731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string transport_type = trans_elem->Name().Namespace();
345731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportInfo tinfo(content.name, transport_type, Candidates());
346731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!ParseCandidates(PROTOCOL_JINGLE, trans_elem,
347731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       trans_parsers, transport_type,
348731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       &tinfo.candidates, error))
349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  tinfos->push_back(tinfo);
352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
353731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
354731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleTransportInfos(const buzz::XmlElement* jingle,
356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const ContentInfos& contents,
357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const TransportParserMap trans_parsers,
358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               TransportInfos* tinfos,
359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               ParseError* error) {
360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* pair_elem
361731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           = jingle->FirstNamed(QN_JINGLE_CONTENT);
362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       pair_elem != NULL;
363731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) {
364731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string content_name;
365731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME,
366731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &content_name, error))
367731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
368731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
369731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const ContentInfo* content = FindContentInfoByName(contents, content_name);
370731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!content)
371731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return BadParse("Unknown content name: " + content_name, error);
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const buzz::XmlElement* trans_elem;
374731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!RequireXmlChild(pair_elem, LN_TRANSPORT, &trans_elem, error))
375731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
377731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseJingleTransportInfo(trans_elem, *content, trans_parsers,
378731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  tinfos, error))
379731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
380731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
381731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbuzz::XmlElement* NewTransportElement(const std::string& name) {
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return new buzz::XmlElement(buzz::QName(true, name, LN_TRANSPORT), true);
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
389731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteCandidates(SignalingProtocol protocol,
390731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const std::string& trans_type,
391731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const Candidates& candidates,
392731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const TransportParserMap& trans_parsers,
393731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     XmlElements* elems,
394731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     WriteError* error) {
395731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TransportParser* trans_parser = GetTransportParser(trans_parsers, trans_type);
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (trans_parser == NULL)
397731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return BadWrite("unknown transport type: " + trans_type, error);
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
399731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return trans_parser->WriteCandidates(protocol, candidates, elems, error);
400731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
401731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteGingleTransportInfos(const TransportInfos& tinfos,
403731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const TransportParserMap& trans_parsers,
404731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               XmlElements* elems,
405731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               WriteError* error) {
406731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (TransportInfos::const_iterator tinfo = tinfos.begin();
407731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       tinfo != tinfos.end(); ++tinfo) {
408731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteCandidates(PROTOCOL_GINGLE,
409731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         tinfo->transport_type, tinfo->candidates,
410731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         trans_parsers, elems, error))
4113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
4143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
417731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteJingleTransportInfo(const TransportInfo& tinfo,
418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              const TransportParserMap& trans_parsers,
419731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              XmlElements* elems,
420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              WriteError* error) {
421731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  XmlElements candidate_elems;
422731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!WriteCandidates(PROTOCOL_JINGLE,
423731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       tinfo.transport_type, tinfo.candidates, trans_parsers,
424731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                       &candidate_elems, error))
425731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
426731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* trans_elem = NewTransportElement(tinfo.transport_type);
428731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlChildren(trans_elem, candidate_elems);
429731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elems->push_back(trans_elem);
430731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
431731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
432731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
433731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WriteJingleContentPair(const std::string name,
434731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            const XmlElements& pair_elems,
435731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                            XmlElements* elems) {
436731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* pair_elem = new buzz::XmlElement(QN_JINGLE_CONTENT);
437731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  pair_elem->SetAttr(QN_JINGLE_CONTENT_NAME, name);
438731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  pair_elem->SetAttr(QN_CREATOR, LN_INITIATOR);
439731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlChildren(pair_elem, pair_elems);
440731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
441731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elems->push_back(pair_elem);
442731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
443731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
444731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteJingleTransportInfos(const TransportInfos& tinfos,
445731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               const TransportParserMap& trans_parsers,
446731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               XmlElements* elems,
447731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                               WriteError* error) {
448731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (TransportInfos::const_iterator tinfo = tinfos.begin();
449731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       tinfo != tinfos.end(); ++tinfo) {
450731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    XmlElements pair_elems;
451731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteJingleTransportInfo(*tinfo, trans_parsers,
452731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  &pair_elems, error))
453731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
454731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
455731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    WriteJingleContentPair(tinfo->content_name, pair_elems, elems);
456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
457731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
461731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickContentParser* GetContentParser(const ContentParserMap& content_parsers,
462731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                const std::string& type) {
4633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ContentParserMap::const_iterator map = content_parsers.find(type);
4643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (map == content_parsers.end()) {
465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return NULL;
466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return map->second;
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
471731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseContentInfo(SignalingProtocol protocol,
472731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const std::string& name,
473731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const std::string& type,
474731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const buzz::XmlElement* elem,
475731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const ContentParserMap& parsers,
476731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      ContentInfos* contents,
477731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      ParseError* error) {
4783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ContentParser* parser = GetContentParser(parsers, type);
4793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parser == NULL)
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return BadParse("unknown application content: " + type, error);
4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const ContentDescription* desc;
483731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!parser->ParseContent(protocol, elem, &desc, error))
4843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
4853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  contents->push_back(ContentInfo(name, type, desc));
487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
490731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseContentType(const buzz::XmlElement* parent_elem,
491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      std::string* content_type,
492731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const buzz::XmlElement** content_elem,
493731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      ParseError* error) {
494731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!RequireXmlChild(parent_elem, LN_DESCRIPTION, content_elem, error))
495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *content_type = (*content_elem)->Name().Namespace();
4983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
501731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleContentInfos(const buzz::XmlElement* session,
502731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentParserMap& content_parsers,
503731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ContentInfos* contents,
504731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string content_type;
5063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const buzz::XmlElement* content_elem;
507731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!ParseContentType(session, &content_type, &content_elem, error))
5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return false;
5093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (content_type == NS_GINGLE_VIDEO) {
5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // A parser parsing audio or video content should look at the
5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // namespace and only parse the codecs relevant to that namespace.
513731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // We use this to control which codecs get parsed: first audio,
514731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // then video.
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    talk_base::scoped_ptr<buzz::XmlElement> audio_elem(
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT));
5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CopyXmlChildren(content_elem, audio_elem.get());
518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP,
519731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          audio_elem.get(), content_parsers,
520731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          contents, error))
521731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
522731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
523731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_VIDEO, NS_JINGLE_RTP,
524731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          content_elem, content_parsers,
525731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          contents, error))
526731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
527731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else if (content_type == NS_GINGLE_AUDIO) {
528731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP,
529731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          content_elem, content_parsers,
530731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          contents, error))
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
533731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentInfo(PROTOCOL_GINGLE, CN_OTHER, content_type,
534731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          content_elem, content_parsers,
535731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          contents, error))
5363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
5373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
541731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleContentInfos(const buzz::XmlElement* jingle,
542731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentParserMap& content_parsers,
543731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ContentInfos* contents,
544731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
545731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* pair_elem
546731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           = jingle->FirstNamed(QN_JINGLE_CONTENT);
547731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       pair_elem != NULL;
548731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) {
549731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string content_name;
550731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME,
551731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        &content_name, error))
552731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
553731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
554731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string content_type;
555731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const buzz::XmlElement* content_elem;
556731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentType(pair_elem, &content_type, &content_elem, error))
557731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
558731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
559731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentInfo(PROTOCOL_JINGLE, content_name, content_type,
560731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          content_elem, content_parsers,
561731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          contents, error))
562731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
563731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
564731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
565731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
566731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
567731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* WriteContentInfo(SignalingProtocol protocol,
568731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   const ContentInfo& content,
569731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   const ContentParserMap& parsers,
570731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   WriteError* error) {
5713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ContentParser* parser = GetContentParser(parsers, content.type);
5723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parser == NULL) {
5733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    BadWrite("unknown content type: " + content.type, error);
5743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
5763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  buzz::XmlElement* elem = NULL;
578731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!parser->WriteContent(protocol, content.description, &elem, error))
5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
5803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return elem;
5823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
5833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
584731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteGingleContentInfos(const ContentInfos& contents,
585731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentParserMap& parsers,
586731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             XmlElements* elems,
587731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             WriteError* error) {
5883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (contents.size() == 1) {
589731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    buzz::XmlElement* elem = WriteContentInfo(
590731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        PROTOCOL_GINGLE, contents.front(), parsers, error);
5913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!elem)
5923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
5933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    elems->push_back(elem);
5953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else if (contents.size() == 2 &&
596731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             contents.at(0).type == NS_JINGLE_RTP &&
597731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             contents.at(1).type == NS_JINGLE_RTP) {
5983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     // Special-case audio + video contents so that they are "merged"
5993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     // into one "video" content.
600731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    buzz::XmlElement* audio = WriteContentInfo(
601731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        PROTOCOL_GINGLE, contents.at(0), parsers, error);
6023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!audio)
6033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
6043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
605731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    buzz::XmlElement* video = WriteContentInfo(
606731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        PROTOCOL_GINGLE, contents.at(1), parsers, error);
6073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!video) {
6083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      delete audio;
6093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
6103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
6113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CopyXmlChildren(audio, video);
6133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    elems->push_back(video);
6143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delete audio;
6153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
6163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return BadWrite("Gingle protocol may only have one content.", error);
6173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
6203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
622731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst TransportInfo* GetTransportInfoByContentName(
623731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const TransportInfos& tinfos, const std::string& content_name) {
624731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (TransportInfos::const_iterator tinfo = tinfos.begin();
625731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       tinfo != tinfos.end(); ++tinfo) {
626731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (content_name == tinfo->content_name) {
627731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return &*tinfo;
628731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
629731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
630731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return NULL;
631731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
632731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
633731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteJingleContentPairs(const ContentInfos& contents,
634731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentParserMap& content_parsers,
635731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const TransportInfos& tinfos,
636731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const TransportParserMap& trans_parsers,
637731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             XmlElements* elems,
638731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             WriteError* error) {
639731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (ContentInfos::const_iterator content = contents.begin();
640731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       content != contents.end(); ++content) {
641731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const TransportInfo* tinfo =
642731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        GetTransportInfoByContentName(tinfos, content->name);
643731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!tinfo)
644731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return BadWrite("No transport for content: " + content->name, error);
645731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
646731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    XmlElements pair_elems;
647731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    buzz::XmlElement* elem = WriteContentInfo(
648731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        PROTOCOL_JINGLE, *content, content_parsers, error);
649731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!elem)
650731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
651731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    pair_elems.push_back(elem);
652731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
653731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteJingleTransportInfo(*tinfo, trans_parsers,
654731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                  &pair_elems, error))
655731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
656731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
657731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    WriteJingleContentPair(content->name, pair_elems, elems);
658731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
659731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
660731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
661731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
662731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseContentType(SignalingProtocol protocol,
663731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      const buzz::XmlElement* action_elem,
664731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      std::string* content_type,
665731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                      ParseError* error) {
6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const buzz::XmlElement* content_elem;
667731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
668731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentType(action_elem, content_type, &content_elem, error))
669731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
670731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
671731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Internally, we only use NS_JINGLE_RTP.
672731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (*content_type == NS_GINGLE_AUDIO ||
673731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        *content_type == NS_GINGLE_VIDEO)
674731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      *content_type = NS_JINGLE_RTP;
675731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
676731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const buzz::XmlElement* pair_elem
677731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        = action_elem->FirstNamed(QN_JINGLE_CONTENT);
678731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (pair_elem == NULL)
679731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return BadParse("No contents found", error);
680731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
681731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseContentType(pair_elem, content_type, &content_elem, error))
682731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
683731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
684731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If there is more than one content type, return an error.
685731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (; pair_elem != NULL;
686731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) {
687731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      std::string content_type2;
688731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (!ParseContentType(pair_elem, &content_type2, &content_elem, error))
689731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        return false;
690731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
691731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (content_type2 != *content_type)
692731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        return BadParse("More than one content type found", error);
693731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
694731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
695731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
696731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
699731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseSessionInitiate(SignalingProtocol protocol,
700731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const buzz::XmlElement* action_elem,
7013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          const ContentParserMap& content_parsers,
702731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const TransportParserMap& trans_parsers,
703731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          SessionInitiate* init,
704731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          ParseError* error) {
705731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  init->owns_contents = true;
706731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
707731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseGingleContentInfos(action_elem, content_parsers,
708731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                 &init->contents, error))
709731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
711731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseGingleTransportInfos(action_elem, init->contents, trans_parsers,
712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   &init->transports, error))
713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
714731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
715731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseJingleContentInfos(action_elem, content_parsers,
716731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                 &init->contents, error))
717731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
718731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
719731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!ParseJingleTransportInfos(action_elem, init->contents, trans_parsers,
720731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   &init->transports, error))
721731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
722731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
723f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
724f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
725f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
726f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
727731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
728731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteSessionInitiate(SignalingProtocol protocol,
729731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const ContentInfos& contents,
730731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const TransportInfos& tinfos,
7313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          const ContentParserMap& content_parsers,
732731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          const TransportParserMap& transport_parsers,
7333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          XmlElements* elems,
7343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          WriteError* error) {
735731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
736731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteGingleContentInfos(contents, content_parsers, elems, error))
737731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
7383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
739731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteGingleTransportInfos(tinfos, transport_parsers,
740731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                   elems, error))
741731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
742731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
743731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!WriteJingleContentPairs(contents, content_parsers,
744731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                 tinfos, transport_parsers,
745731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                 elems, error))
746731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
747731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
7483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
750f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
751f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
752731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseSessionAccept(SignalingProtocol protocol,
753731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        const buzz::XmlElement* action_elem,
7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        const ContentParserMap& content_parsers,
755731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        const TransportParserMap& transport_parsers,
756731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        SessionAccept* accept,
757731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        ParseError* error) {
758731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return ParseSessionInitiate(protocol, action_elem,
759731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              content_parsers, transport_parsers,
760731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              accept, error);
761f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
763731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteSessionAccept(SignalingProtocol protocol,
764731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        const ContentInfos& contents,
765731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        const TransportInfos& tinfos,
7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        const ContentParserMap& content_parsers,
767731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                        const TransportParserMap& transport_parsers,
7683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        XmlElements* elems,
7693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                        WriteError* error) {
770731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return WriteSessionInitiate(protocol, contents, tinfos,
771731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              content_parsers, transport_parsers,
772731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              elems, error);
773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
775731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseSessionTerminate(SignalingProtocol protocol,
776731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           const buzz::XmlElement* action_elem,
777731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           SessionTerminate* term,
778731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           ParseError* error) {
779731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
780731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const buzz::XmlElement* reason_elem = action_elem->FirstElement();
781731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (reason_elem != NULL) {
782731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      term->reason = reason_elem->Name().LocalPart();
783731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      const buzz::XmlElement *debug_elem = reason_elem->FirstElement();
784731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (debug_elem != NULL) {
785731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        term->debug_reason = debug_elem->Name().LocalPart();
786731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
787731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
788731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return true;
789731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
790731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const buzz::XmlElement* reason_elem =
791731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        action_elem->FirstNamed(QN_JINGLE_REASON);
792731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (reason_elem) {
793731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      reason_elem = reason_elem->FirstElement();
794731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (reason_elem) {
795731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        term->reason = reason_elem->Name().LocalPart();
796731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
797f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
798731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return true;
799f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
800f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
801f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
802731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WriteSessionTerminate(SignalingProtocol protocol,
803731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           const SessionTerminate& term,
804731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           XmlElements* elems) {
805731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
806731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elems->push_back(new buzz::XmlElement(
807731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        buzz::QName(true, NS_GINGLE, term.reason)));
808731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
809731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!term.reason.empty()) {
810731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      buzz::XmlElement* reason_elem = new buzz::XmlElement(QN_JINGLE_REASON);
811731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      reason_elem->AddElement(new buzz::XmlElement(
812731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          buzz::QName(true, NS_JINGLE, term.reason)));
813731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      elems->push_back(reason_elem);
814731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
815731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
816f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
817f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
818731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseTransportInfos(SignalingProtocol protocol,
819731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         const buzz::XmlElement* action_elem,
820731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         const ContentInfos& contents,
821731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         const TransportParserMap& trans_parsers,
822731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         TransportInfos* tinfos,
823731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         ParseError* error) {
824731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
825731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ParseGingleTransportInfos(
826731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        action_elem, contents, trans_parsers, tinfos, error);
827731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
828731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return ParseJingleTransportInfos(
829731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        action_elem, contents, trans_parsers, tinfos, error);
830731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
831f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
832f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
833731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool WriteTransportInfos(SignalingProtocol protocol,
834731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         const TransportInfos& tinfos,
835731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         const TransportParserMap& trans_parsers,
836731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         XmlElements* elems,
837731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                         WriteError* error) {
838731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
839731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return WriteGingleTransportInfos(tinfos, trans_parsers,
840731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     elems, error);
841731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
842731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return WriteJingleTransportInfos(tinfos, trans_parsers,
843731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     elems, error);
844731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
845f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
846f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
847dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ParseSessionNotify(const buzz::XmlElement* action_elem,
848dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        SessionNotify* notify, ParseError* error) {
849dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const buzz::XmlElement* notify_elem;
850dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (notify_elem = action_elem->FirstNamed(QN_GINGLE_NOTIFY);
851dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      notify_elem != NULL;
852dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      notify_elem = notify_elem->NextNamed(QN_GINGLE_NOTIFY)) {
853dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Note that a subsequent notify element for the same user will override a
854dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // previous.  We don't merge them.
855dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    std::string nick(notify_elem->Attr(QN_GINGLE_NOTIFY_NICK));
856dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (nick != buzz::STR_EMPTY) {
857dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      MediaSources sources;
858dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      const buzz::XmlElement* source_elem;
859dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      for (source_elem = notify_elem->FirstNamed(QN_GINGLE_NOTIFY_SOURCE);
860dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          source_elem != NULL;
861dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          source_elem = source_elem->NextNamed(QN_GINGLE_NOTIFY_SOURCE)) {
862dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        std::string ssrc = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_SSRC);
863dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (ssrc != buzz::STR_EMPTY) {
864dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::string mtype = source_elem->Attr(QN_GINGLE_NOTIFY_SOURCE_MTYPE);
865dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_AUDIO) {
866dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            sources.audio_ssrc = strtoul(ssrc.c_str(), NULL, 10);
867dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          } else if (mtype == GINGLE_NOTIFY_SOURCE_MTYPE_VIDEO) {
868dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            sources.video_ssrc = strtoul(ssrc.c_str(), NULL, 10);
869dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          }
870dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
871dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
872dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
873dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      notify->nickname_to_sources.insert(
874dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          std::pair<std::string, MediaSources>(nick, sources));
875dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
876dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
877dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
878dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
879dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
880dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
8814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetUriTarget(const std::string& prefix, const std::string& str,
8824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                  std::string* after) {
8834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  size_t pos = str.find(prefix);
8844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (pos == std::string::npos)
8854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
8864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  *after = str.substr(pos + prefix.size(), std::string::npos);
8884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
8894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
8904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
891dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool ParseSessionUpdate(const buzz::XmlElement* action_elem,
892dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        SessionUpdate* update, ParseError* error) {
893dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO: Parse the update message.
894dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
895dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
896dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
897dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid WriteSessionView(const SessionView& view, XmlElements* elems) {
898dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::vector<VideoViewRequest>::const_iterator it;
899dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (it = view.view_requests.begin(); it != view.view_requests.end(); it++) {
900dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    talk_base::scoped_ptr<buzz::XmlElement> view_elem(
901dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        new buzz::XmlElement(QN_GINGLE_VIEW));
902dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (view_elem.get() == NULL) {
903dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
904dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
905dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
906dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    view_elem->SetAttr(QN_GINGLE_VIEW_TYPE, GINGLE_VIEW_TYPE_STATIC);
907dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    view_elem->SetAttr(QN_GINGLE_VIEW_NICK, it->nick_name);
908dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    view_elem->SetAttr(QN_GINGLE_VIEW_MEDIA_TYPE,
909dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        GINGLE_VIEW_MEDIA_TYPE_VIDEO);
910dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // A 32-bit uint, expressed as decimal, has a max of 10 digits, plus one
912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // for the null.
913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    char str[11];
914dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    int result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->ssrc);
915dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (result < 0 || result >= ARRAY_SIZE(str)) {
916dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
917dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
918dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    view_elem->SetAttr(QN_GINGLE_VIEW_SSRC, str);
919dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
920dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Include video-specific parameters in a child <params> element.
921dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    talk_base::scoped_ptr<buzz::XmlElement> params_elem(
922dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        new buzz::XmlElement(QN_GINGLE_VIEW_PARAMS));
923dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (params_elem.get() == NULL) {
924dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
925dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
926dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
927dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->width);
928dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (result < 0 || result >= ARRAY_SIZE(str)) {
929dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
930dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
931dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_WIDTH, str);
932dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
933dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->height);
934dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (result < 0 || result >= ARRAY_SIZE(str)) {
935dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
936dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
937dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_HEIGHT, str);
938dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
939dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    result = talk_base::sprintfn(str, ARRAY_SIZE(str), "%u", it->framerate);
940dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (result < 0 || result >= ARRAY_SIZE(str)) {
941dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      continue;
942dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
943dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    params_elem->SetAttr(QN_GINGLE_VIEW_PARAMS_FRAMERATE, str);
944dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
945dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    view_elem->AddElement(params_elem.release());
946dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    elems->push_back(view_elem.release());
947dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
948dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
949dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
9504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool FindSessionRedirect(const buzz::XmlElement* stanza,
9514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                         SessionRedirect* redirect) {
9524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR);
9534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (error_elem == NULL)
9544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
9554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
9564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const buzz::XmlElement* redirect_elem =
9574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      error_elem->FirstNamed(QN_GINGLE_REDIRECT);
9584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (redirect_elem == NULL)
9594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    redirect_elem = error_elem->FirstNamed(buzz::QN_STANZA_REDIRECT);
9604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (redirect_elem == NULL)
9614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
9624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
9634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!GetUriTarget(STR_REDIRECT_PREFIX, redirect_elem->BodyText(),
9644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                    &redirect->target))
9654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
9664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
9674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
9684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
9694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
970f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // namespace cricket
971