http: implement 401 response handling
[siplcs.git] / src / core / sipe-dialog.c
blob7d58d5b3ad539d469752194cd44583718cfca095
1 /**
2 * @file sipe-dialog.c
4 * pidgin-sipe
6 * Copyright (C) 2009-11 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-core.h"
30 #include "sipe-common.h"
31 #include "sipmsg.h"
32 #include "sipe-backend.h"
33 #include "sipe-dialog.h"
34 #include "sipe-session.h"
35 #include "sipe-utils.h"
37 void sipe_dialog_free(struct sip_dialog *dialog)
39 GSList *entry;
40 void *data;
42 if (!dialog) return;
44 g_free(dialog->with);
45 g_free(dialog->endpoint_GUID);
46 entry = dialog->routes;
47 while (entry) {
48 data = entry->data;
49 entry = g_slist_remove(entry, data);
50 g_free(data);
52 entry = dialog->supported;
53 while (entry) {
54 data = entry->data;
55 entry = g_slist_remove(entry, data);
56 g_free(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);
70 g_free(dialog);
73 struct sip_dialog *sipe_dialog_add(struct sip_session *session)
75 struct sip_dialog *dialog = g_new0(struct sip_dialog, 1);
76 session->dialogs = g_slist_append(session->dialogs, dialog);
77 return(dialog);
80 static struct sip_dialog *
81 sipe_dialog_find_3(struct sip_session *session,
82 struct sip_dialog *dialog_in)
84 if (session && dialog_in) {
85 SIPE_DIALOG_FOREACH {
86 if ( dialog_in->callid &&
87 dialog_in->ourtag &&
88 dialog_in->theirtag &&
90 dialog->callid &&
91 dialog->ourtag &&
92 dialog->theirtag &&
94 sipe_strcase_equal(dialog_in->callid, dialog->callid) &&
95 sipe_strcase_equal(dialog_in->ourtag, dialog->ourtag) &&
96 sipe_strcase_equal(dialog_in->theirtag, dialog->theirtag))
98 SIPE_DEBUG_INFO("sipe_dialog_find_3 who='%s'",
99 dialog->with ? dialog->with : "");
100 return dialog;
102 } SIPE_DIALOG_FOREACH_END;
104 return NULL;
107 struct sip_dialog *sipe_dialog_find(struct sip_session *session,
108 const gchar *who)
110 if (session && who) {
111 SIPE_DIALOG_FOREACH {
112 if (dialog->with && sipe_strcase_equal(who, dialog->with)) {
113 SIPE_DEBUG_INFO("sipe_dialog_find who='%s'", who);
114 return dialog;
116 } SIPE_DIALOG_FOREACH_END;
118 return NULL;
121 void sipe_dialog_remove(struct sip_session *session, const gchar *who)
123 struct sip_dialog *dialog = sipe_dialog_find(session, who);
124 if (dialog) {
125 SIPE_DEBUG_INFO("sipe_dialog_remove who='%s' with='%s'", who, dialog->with ? dialog->with : "");
126 session->dialogs = g_slist_remove(session->dialogs, dialog);
127 sipe_dialog_free(dialog);
131 void
132 sipe_dialog_remove_3(struct sip_session *session,
133 struct sip_dialog *dialog_in)
135 struct sip_dialog *dialog = sipe_dialog_find_3(session, dialog_in);
136 if (dialog) {
137 SIPE_DEBUG_INFO("sipe_dialog_remove_3 with='%s'",
138 dialog->with ? dialog->with : "");
139 session->dialogs = g_slist_remove(session->dialogs, dialog);
140 sipe_dialog_free(dialog);
144 void sipe_dialog_remove_all(struct sip_session *session)
146 GSList *entry = session->dialogs;
147 while (entry) {
148 struct sip_dialog *dialog = entry->data;
149 entry = g_slist_remove(entry, dialog);
150 sipe_dialog_free(dialog);
154 static void sipe_dialog_parse_routes(struct sip_dialog *dialog,
155 const struct sipmsg *msg,
156 gboolean outgoing)
158 GSList *hdr = msg->headers;
159 gchar *contact = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Contact"), "<", ">", NULL);
161 /* Remove old routes */
162 while (dialog->routes) {
163 void *data = dialog->routes->data;
164 dialog->routes = g_slist_remove(dialog->routes, data);
165 g_free(data);
167 g_free(dialog->request);
168 dialog->request = NULL;
170 while (hdr) {
171 struct sipnameval *elem = hdr->data;
172 if (sipe_strcase_equal(elem->name, "Record-Route")) {
173 gchar **parts = g_strsplit(elem->value, ",", 0);
174 gchar **part = parts;
176 while (*part) {
177 SIPE_DEBUG_INFO("sipe_dialog_parse_routes: route %s", *part);
178 dialog->routes = g_slist_append(dialog->routes,
179 g_strdup(*part));
180 part++;
182 g_strfreev(parts);
184 hdr = g_slist_next(hdr);
186 if (outgoing) {
187 dialog->routes = g_slist_reverse(dialog->routes);
190 if (contact) {
191 dialog->request = contact;
194 /* logic for strict router only - RFC3261 - 12.2.1.1 */
195 /* @TODO: proper check for presence of 'lr' PARAMETER in URI */
196 if (dialog->routes && !strstr(dialog->routes->data, ";lr")) {
197 gchar *route = dialog->routes->data;
198 dialog->request = sipmsg_find_part_of_header(route, "<", ">", NULL);
199 SIPE_DEBUG_INFO("sipe_dialog_parse_routes: strict route, contact %s", dialog->request);
200 dialog->routes = g_slist_remove(dialog->routes, route);
201 g_free(route);
202 if (contact) {
203 dialog->routes = g_slist_append(dialog->routes,
204 g_strdup_printf("<%s>", contact));
205 g_free(contact);
210 static void
211 sipe_get_supported_header(const struct sipmsg *msg,
212 struct sip_dialog *dialog,
213 SIPE_UNUSED_PARAMETER gboolean outgoing)
215 GSList *hdr = msg->headers;
216 struct sipnameval *elem;
217 while(hdr)
219 elem = hdr->data;
220 if (sipe_strcase_equal(elem->name, "Supported")
221 && !g_slist_find_custom(dialog->supported, elem->value, (GCompareFunc)g_ascii_strcasecmp))
223 dialog->supported = g_slist_append(dialog->supported, g_strdup(elem->value));
226 hdr = g_slist_next(hdr);
230 static gchar *find_tag(const gchar *hdr)
232 gchar * tag = sipmsg_find_part_of_header (hdr, "tag=", ";", NULL);
233 if (!tag) {
234 // In case it's at the end and there's no trailing ;
235 tag = sipmsg_find_part_of_header (hdr, "tag=", NULL, NULL);
237 return tag;
240 void sipe_dialog_parse(struct sip_dialog *dialog,
241 const struct sipmsg *msg,
242 gboolean outgoing)
244 gchar *us = outgoing ? "From" : "To";
245 gchar *them = outgoing ? "To" : "From";
246 const gchar *session_expires_header;
248 g_free(dialog->ourtag);
249 g_free(dialog->theirtag);
251 dialog->ourtag = find_tag(sipmsg_find_header(msg, us));
252 dialog->theirtag = find_tag(sipmsg_find_header(msg, them));
253 if (!dialog->theirepid) {
254 dialog->theirepid = sipmsg_find_part_of_header(sipmsg_find_header(msg, them), "epid=", ";", NULL);
255 if (!dialog->theirepid) {
256 dialog->theirepid = sipmsg_find_part_of_header(sipmsg_find_header(msg, them), "epid=", NULL, NULL);
260 // Catch a tag on the end of the To Header and get rid of it.
261 if (dialog->theirepid && strstr(dialog->theirepid, "tag=")) {
262 dialog->theirepid = strtok(dialog->theirepid, ";");
265 if ((session_expires_header = sipmsg_find_header(msg, "Session-Expires"))) {
266 dialog->expires = atoi(session_expires_header);
269 sipe_dialog_parse_routes(dialog, msg, outgoing);
270 sipe_get_supported_header(msg, dialog, outgoing);
274 Local Variables:
275 mode: c
276 c-file-style: "bsd"
277 indent-tabs-mode: t
278 tab-width: 8
279 End: