core cleanup: rename core & backend API headers
[siplcs.git] / src / core / sipe-dialog.c
blob018572394395d1e02c91cfc7130b45ede04be1a0
1 /**
2 * @file sipe-dialog.c
4 * pidgin-sipe
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
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
27 #include <glib.h>
29 #include "sipe-common.h"
30 #include "sipmsg.h"
31 #include "sipe-backend.h"
32 #include "sipe-dialog.h"
33 #include "sipe-session.h"
34 #include "sipe-utils.h"
36 void sipe_dialog_free(struct sip_dialog *dialog)
38 GSList *entry;
39 void *data;
41 if (!dialog) return;
43 g_free(dialog->with);
44 g_free(dialog->endpoint_GUID);
45 entry = dialog->routes;
46 while (entry) {
47 data = entry->data;
48 entry = g_slist_remove(entry, data);
49 g_free(data);
51 entry = dialog->supported;
52 while (entry) {
53 data = entry->data;
54 entry = g_slist_remove(entry, data);
55 g_free(data);
58 g_free(dialog->callid);
59 g_free(dialog->ourtag);
60 g_free(dialog->theirtag);
61 g_free(dialog->theirepid);
62 g_free(dialog->request);
64 g_free(dialog);
67 void sipe_subscription_free(struct sip_subscription *subscription)
69 if (!subscription) return;
71 g_free(subscription->event);
72 /* NOTE: use cast to prevent BAD_FREE warning from Coverity */
73 sipe_dialog_free((struct sip_dialog *) subscription);
76 struct sip_dialog *sipe_dialog_add(struct sip_session *session)
78 struct sip_dialog *dialog = g_new0(struct sip_dialog, 1);
79 session->dialogs = g_slist_append(session->dialogs, dialog);
80 return(dialog);
83 static struct sip_dialog *
84 sipe_dialog_find_3(struct sip_session *session,
85 struct sip_dialog *dialog_in)
87 if (session && dialog_in) {
88 SIPE_DIALOG_FOREACH {
89 if ( dialog_in->callid &&
90 dialog_in->ourtag &&
91 dialog_in->theirtag &&
93 dialog->callid &&
94 dialog->ourtag &&
95 dialog->theirtag &&
97 sipe_strcase_equal(dialog_in->callid, dialog->callid) &&
98 sipe_strcase_equal(dialog_in->ourtag, dialog->ourtag) &&
99 sipe_strcase_equal(dialog_in->theirtag, dialog->theirtag))
101 SIPE_DEBUG_INFO("sipe_dialog_find_3 who='%s'",
102 dialog->with ? dialog->with : "");
103 return dialog;
105 } SIPE_DIALOG_FOREACH_END;
107 return NULL;
110 struct sip_dialog *sipe_dialog_find(struct sip_session *session,
111 const gchar *who)
113 if (session && who) {
114 SIPE_DIALOG_FOREACH {
115 if (dialog->with && sipe_strcase_equal(who, dialog->with)) {
116 SIPE_DEBUG_INFO("sipe_dialog_find who='%s'", who);
117 return dialog;
119 } SIPE_DIALOG_FOREACH_END;
121 return NULL;
124 void sipe_dialog_remove(struct sip_session *session, const gchar *who)
126 struct sip_dialog *dialog = sipe_dialog_find(session, who);
127 if (dialog) {
128 SIPE_DEBUG_INFO("sipe_dialog_remove who='%s' with='%s'", who, dialog->with ? dialog->with : "");
129 session->dialogs = g_slist_remove(session->dialogs, dialog);
130 sipe_dialog_free(dialog);
134 void
135 sipe_dialog_remove_3(struct sip_session *session,
136 struct sip_dialog *dialog_in)
138 struct sip_dialog *dialog = sipe_dialog_find_3(session, dialog_in);
139 if (dialog) {
140 SIPE_DEBUG_INFO("sipe_dialog_remove_3 with='%s'",
141 dialog->with ? dialog->with : "");
142 session->dialogs = g_slist_remove(session->dialogs, dialog);
143 sipe_dialog_free(dialog);
147 void sipe_dialog_remove_all(struct sip_session *session)
149 GSList *entry = session->dialogs;
150 while (entry) {
151 struct sip_dialog *dialog = entry->data;
152 entry = g_slist_remove(entry, dialog);
153 sipe_dialog_free(dialog);
157 void sipe_dialog_parse_routes(struct sip_dialog *dialog,
158 const struct sipmsg *msg,
159 gboolean outgoing)
161 GSList *hdr = msg->headers;
162 gchar *contact = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Contact"), "<", ">", NULL);
164 /* Remove old routes */
165 while (dialog->routes) {
166 void *data = dialog->routes->data;
167 dialog->routes = g_slist_remove(dialog->routes, data);
168 g_free(data);
170 g_free(dialog->request);
171 dialog->request = NULL;
173 while (hdr) {
174 struct sipnameval *elem = hdr->data;
175 if (sipe_strcase_equal(elem->name, "Record-Route")) {
176 gchar **parts = g_strsplit(elem->value, ",", 0);
177 gchar **part = parts;
179 while (*part) {
180 gchar *route = sipmsg_find_part_of_header(*part, "<", ">", NULL);
181 SIPE_DEBUG_INFO("sipe_dialog_parse_routes: route %s", route);
182 dialog->routes = g_slist_append(dialog->routes, route);
183 part++;
186 g_strfreev(parts);
188 hdr = g_slist_next(hdr);
190 if (outgoing) {
191 dialog->routes = g_slist_reverse(dialog->routes);
194 if (contact) {
195 dialog->request = contact;
198 /* logic for strict router only - RFC3261 - 12.2.1.1 */
199 /* @TODO: proper check for presence of 'lr' PARAMETER in URI */
200 if (dialog->routes && !strstr(dialog->routes->data, ";lr")) {
201 dialog->request = dialog->routes->data;
202 dialog->routes = g_slist_remove(dialog->routes, dialog->routes->data);
203 if (contact) {
204 dialog->routes = g_slist_append(dialog->routes, contact);
209 static void
210 sipe_get_supported_header(const struct sipmsg *msg,
211 struct sip_dialog *dialog,
212 SIPE_UNUSED_PARAMETER gboolean outgoing)
214 GSList *hdr = msg->headers;
215 struct sipnameval *elem;
216 while(hdr)
218 elem = hdr->data;
219 if (sipe_strcase_equal(elem->name, "Supported")
220 && !g_slist_find_custom(dialog->supported, elem->value, (GCompareFunc)g_ascii_strcasecmp))
222 dialog->supported = g_slist_append(dialog->supported, g_strdup(elem->value));
225 hdr = g_slist_next(hdr);
229 static gchar *find_tag(const gchar *hdr)
231 gchar * tag = sipmsg_find_part_of_header (hdr, "tag=", ";", NULL);
232 if (!tag) {
233 // In case it's at the end and there's no trailing ;
234 tag = sipmsg_find_part_of_header (hdr, "tag=", NULL, NULL);
236 return tag;
239 void sipe_dialog_parse(struct sip_dialog *dialog,
240 const struct sipmsg *msg,
241 gboolean outgoing)
243 gchar *us = outgoing ? "From" : "To";
244 gchar *them = outgoing ? "To" : "From";
245 const gchar *session_expires_header;
247 g_free(dialog->ourtag);
248 g_free(dialog->theirtag);
250 dialog->ourtag = find_tag(sipmsg_find_header(msg, us));
251 dialog->theirtag = find_tag(sipmsg_find_header(msg, them));
252 if (!dialog->theirepid) {
253 dialog->theirepid = sipmsg_find_part_of_header(sipmsg_find_header(msg, them), "epid=", ";", NULL);
254 if (!dialog->theirepid) {
255 dialog->theirepid = sipmsg_find_part_of_header(sipmsg_find_header(msg, them), "epid=", NULL, NULL);
259 // Catch a tag on the end of the To Header and get rid of it.
260 if (dialog->theirepid && strstr(dialog->theirepid, "tag=")) {
261 dialog->theirepid = strtok(dialog->theirepid, ";");
264 if ((session_expires_header = sipmsg_find_header(msg, "Session-Expires"))) {
265 dialog->expires = atoi(session_expires_header);
268 sipe_dialog_parse_routes(dialog, msg, outgoing);
269 sipe_get_supported_header(msg, dialog, outgoing);
273 Local Variables:
274 mode: c
275 c-file-style: "bsd"
276 indent-tabs-mode: t
277 tab-width: 8
278 End: