6 * Copyright (C) 2009 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "sipe-common.h"
31 #include "sipe-backend.h"
32 #include "sipe-dialog.h"
33 #include "sipe-session.h"
34 #include "sipe-utils.h"
37 void sipe_dialog_free(struct sip_dialog
*dialog
)
45 g_free(dialog
->endpoint_GUID
);
46 entry
= dialog
->routes
;
49 entry
= g_slist_remove(entry
, data
);
52 entry
= dialog
->supported
;
55 entry
= g_slist_remove(entry
, data
);
59 while (dialog
->filetransfers
) {
60 struct sipe_file_transfer
*ft
= dialog
->filetransfers
->data
;
61 sipe_core_ft_deallocate(ft
);
64 g_free(dialog
->callid
);
65 g_free(dialog
->ourtag
);
66 g_free(dialog
->theirtag
);
67 g_free(dialog
->theirepid
);
68 g_free(dialog
->request
);
73 void sipe_subscription_free(struct sip_subscription
*subscription
)
75 if (!subscription
) return;
77 g_free(subscription
->event
);
78 /* NOTE: use cast to prevent BAD_FREE warning from Coverity */
79 sipe_dialog_free((struct sip_dialog
*) subscription
);
82 struct sip_dialog
*sipe_dialog_add(struct sip_session
*session
)
84 struct sip_dialog
*dialog
= g_new0(struct sip_dialog
, 1);
85 session
->dialogs
= g_slist_append(session
->dialogs
, dialog
);
89 static struct sip_dialog
*
90 sipe_dialog_find_3(struct sip_session
*session
,
91 struct sip_dialog
*dialog_in
)
93 if (session
&& dialog_in
) {
95 if ( dialog_in
->callid
&&
97 dialog_in
->theirtag
&&
103 sipe_strcase_equal(dialog_in
->callid
, dialog
->callid
) &&
104 sipe_strcase_equal(dialog_in
->ourtag
, dialog
->ourtag
) &&
105 sipe_strcase_equal(dialog_in
->theirtag
, dialog
->theirtag
))
107 SIPE_DEBUG_INFO("sipe_dialog_find_3 who='%s'",
108 dialog
->with
? dialog
->with
: "");
111 } SIPE_DIALOG_FOREACH_END
;
116 struct sip_dialog
*sipe_dialog_find(struct sip_session
*session
,
119 if (session
&& who
) {
120 SIPE_DIALOG_FOREACH
{
121 if (dialog
->with
&& sipe_strcase_equal(who
, dialog
->with
)) {
122 SIPE_DEBUG_INFO("sipe_dialog_find who='%s'", who
);
125 } SIPE_DIALOG_FOREACH_END
;
130 void sipe_dialog_remove(struct sip_session
*session
, const gchar
*who
)
132 struct sip_dialog
*dialog
= sipe_dialog_find(session
, who
);
134 SIPE_DEBUG_INFO("sipe_dialog_remove who='%s' with='%s'", who
, dialog
->with
? dialog
->with
: "");
135 session
->dialogs
= g_slist_remove(session
->dialogs
, dialog
);
136 sipe_dialog_free(dialog
);
141 sipe_dialog_remove_3(struct sip_session
*session
,
142 struct sip_dialog
*dialog_in
)
144 struct sip_dialog
*dialog
= sipe_dialog_find_3(session
, dialog_in
);
146 SIPE_DEBUG_INFO("sipe_dialog_remove_3 with='%s'",
147 dialog
->with
? dialog
->with
: "");
148 session
->dialogs
= g_slist_remove(session
->dialogs
, dialog
);
149 sipe_dialog_free(dialog
);
153 void sipe_dialog_remove_all(struct sip_session
*session
)
155 GSList
*entry
= session
->dialogs
;
157 struct sip_dialog
*dialog
= entry
->data
;
158 entry
= g_slist_remove(entry
, dialog
);
159 sipe_dialog_free(dialog
);
163 void sipe_dialog_parse_routes(struct sip_dialog
*dialog
,
164 const struct sipmsg
*msg
,
167 GSList
*hdr
= msg
->headers
;
168 gchar
*contact
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, "Contact"), "<", ">", NULL
);
170 /* Remove old routes */
171 while (dialog
->routes
) {
172 void *data
= dialog
->routes
->data
;
173 dialog
->routes
= g_slist_remove(dialog
->routes
, data
);
176 g_free(dialog
->request
);
177 dialog
->request
= NULL
;
180 struct sipnameval
*elem
= hdr
->data
;
181 if (sipe_strcase_equal(elem
->name
, "Record-Route")) {
182 gchar
**parts
= g_strsplit(elem
->value
, ",", 0);
183 gchar
**part
= parts
;
186 gchar
*route
= sipmsg_find_part_of_header(*part
, "<", ">", NULL
);
187 SIPE_DEBUG_INFO("sipe_dialog_parse_routes: route %s", route
);
188 dialog
->routes
= g_slist_append(dialog
->routes
, route
);
194 hdr
= g_slist_next(hdr
);
197 dialog
->routes
= g_slist_reverse(dialog
->routes
);
201 dialog
->request
= contact
;
204 /* logic for strict router only - RFC3261 - 12.2.1.1 */
205 /* @TODO: proper check for presence of 'lr' PARAMETER in URI */
206 if (dialog
->routes
&& !strstr(dialog
->routes
->data
, ";lr")) {
207 dialog
->request
= dialog
->routes
->data
;
208 dialog
->routes
= g_slist_remove(dialog
->routes
, dialog
->routes
->data
);
210 dialog
->routes
= g_slist_append(dialog
->routes
, contact
);
216 sipe_get_supported_header(const struct sipmsg
*msg
,
217 struct sip_dialog
*dialog
,
218 SIPE_UNUSED_PARAMETER gboolean outgoing
)
220 GSList
*hdr
= msg
->headers
;
221 struct sipnameval
*elem
;
225 if (sipe_strcase_equal(elem
->name
, "Supported")
226 && !g_slist_find_custom(dialog
->supported
, elem
->value
, (GCompareFunc
)g_ascii_strcasecmp
))
228 dialog
->supported
= g_slist_append(dialog
->supported
, g_strdup(elem
->value
));
231 hdr
= g_slist_next(hdr
);
235 static gchar
*find_tag(const gchar
*hdr
)
237 gchar
* tag
= sipmsg_find_part_of_header (hdr
, "tag=", ";", NULL
);
239 // In case it's at the end and there's no trailing ;
240 tag
= sipmsg_find_part_of_header (hdr
, "tag=", NULL
, NULL
);
245 void sipe_dialog_parse(struct sip_dialog
*dialog
,
246 const struct sipmsg
*msg
,
249 gchar
*us
= outgoing
? "From" : "To";
250 gchar
*them
= outgoing
? "To" : "From";
251 const gchar
*session_expires_header
;
253 g_free(dialog
->ourtag
);
254 g_free(dialog
->theirtag
);
256 dialog
->ourtag
= find_tag(sipmsg_find_header(msg
, us
));
257 dialog
->theirtag
= find_tag(sipmsg_find_header(msg
, them
));
258 if (!dialog
->theirepid
) {
259 dialog
->theirepid
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, them
), "epid=", ";", NULL
);
260 if (!dialog
->theirepid
) {
261 dialog
->theirepid
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, them
), "epid=", NULL
, NULL
);
265 // Catch a tag on the end of the To Header and get rid of it.
266 if (dialog
->theirepid
&& strstr(dialog
->theirepid
, "tag=")) {
267 dialog
->theirepid
= strtok(dialog
->theirepid
, ";");
270 if ((session_expires_header
= sipmsg_find_header(msg
, "Session-Expires"))) {
271 dialog
->expires
= atoi(session_expires_header
);
274 sipe_dialog_parse_routes(dialog
, msg
, outgoing
);
275 sipe_get_supported_header(msg
, dialog
, outgoing
);