summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPekka Pessi <Pekka.Pessi@nokia.com>2011-01-31 17:32:55 +0200
committerPekka Pessi <Pekka.Pessi@nokia.com>2011-02-02 17:22:06 +0200
commit7842fdc032e068528b924226c7ed24ffd603257a (patch)
treecb1eb052e6a5a661875f563c7fdedfc1c84df9a1
parent92c23c73853783f34e861599391416bae37cbf5f (diff)
tpsip/handles: add
New SIP handle management functions: - tpsip_handle_ensure () - tpsip_handle_by_requestor () (replaces tpsip_handle_parse_from()) - tpsip_handle_unref () - tpsip_handle_inspect () - tpsip_handle_inspect_uri () (replaces tpsip_conn_get_contact_url()) Functions tpsip_handle_normalize() and tpsip_normalize_contact () are also moved to tpsip/handles.
-rw-r--r--src/sip-connection-helpers.c202
-rw-r--r--tpsip/Makefile.am2
-rw-r--r--tpsip/handles.c345
-rw-r--r--tpsip/handles.h47
4 files changed, 394 insertions, 202 deletions
diff --git a/src/sip-connection-helpers.c b/src/sip-connection-helpers.c
index 8ad9b42..09f7fb3 100644
--- a/src/sip-connection-helpers.c
+++ b/src/sip-connection-helpers.c
@@ -674,208 +674,6 @@ tpsip_conn_discover_stun_server (TpsipConnection *conn)
g_free (srv_domain);
}
-static gboolean
-priv_is_host (const gchar* str)
-{
- static GRegex *host_regex = NULL;
-
-#define DOMAIN "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
-#define TLD "[a-z]([-a-z0-9]*[a-z0-9])?"
-
- if (host_regex == NULL)
- {
- GError *error = NULL;
-
- host_regex = g_regex_new ("^("
- "("DOMAIN"\\.)*"TLD"\\.?|" /* host name */
- "[0-9]{1,3}(\\.[0-9]{1,3}){3}|" /* IPv4 address */
- "\\[[0-9a-f:.]\\]" /* IPv6 address, sloppily */
- ")$",
- G_REGEX_CASELESS | G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
-
- if (error != NULL)
- g_error ("failed to compile the host regex: %s", error->message);
- }
-
-#undef DOMAIN
-#undef TLD
-
- return g_regex_match (host_regex, str, 0, NULL);
-}
-
-static gboolean
-priv_is_tel_num (const gchar *str)
-{
- static GRegex *tel_num_regex = NULL;
-
- if (tel_num_regex == NULL)
- {
- GError *error = NULL;
-
- tel_num_regex = g_regex_new (
- "^\\s*[\\+(]?\\s*[0-9][-.0-9()\\s]*$",
- G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
-
- if (error != NULL)
- g_error ("failed to compile the telephone number regex: %s", error->message);
- }
-
- return g_regex_match (tel_num_regex, str, 0, NULL);
-}
-
-/* Strip the non-essential characters from a string regarded as
- * a telephone number */
-static gchar *
-priv_strip_tel_num (const gchar *fuzzy)
-{
- static GRegex *cruft_regex = NULL;
-
- if (cruft_regex == NULL)
- {
- GError *error = NULL;
-
- cruft_regex = g_regex_new ("[^+0-9]+",
- G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
-
- if (error != NULL)
- g_error ("failed to compile the non-essential telephone number cruft regex: %s", error->message);
- }
-
- return g_regex_replace_literal (cruft_regex, fuzzy, -1, 0, "", 0, NULL);
-}
-
-static const char *
-priv_lowercase_url_part (su_home_t *home, const char *src)
-{
- size_t n = 0;
- size_t i;
- char *res;
-
- for (i = 0; src[i]; i++)
- {
- if (g_ascii_isupper (src[i]))
- {
- n = i + strlen (src + i);
- break;
- }
- }
-
- if (!src[i])
- return src;
-
- res = su_alloc (home, n + 1);
- memcpy (res, src, i);
- for (; i < n; i++)
- res[i] = g_ascii_tolower (src[i]);
- res[i] = '\0';
-
- return (const char *) res;
-}
-
-#define TPSIP_RESERVED_CHARS_ALLOWED_IN_USERNAME "!*'()&=+$,;?/"
-
-gchar *
-tpsip_normalize_contact (const gchar *sipuri,
- const url_t *base_url,
- const gchar *transport,
- GError **error)
-{
- su_home_t home[1] = { SU_HOME_INIT(home) };
- url_t *url;
- gchar *retval = NULL;
- char *c;
-
- url = url_make (home, sipuri);
-
- if (url == NULL ||
- (url->url_scheme == NULL && url->url_user == NULL))
- {
- /* we got username or phone number, local to our domain */
- gchar *user;
-
- if (base_url == NULL || base_url->url_host == NULL)
- {
- WARNING ("bare name given, but no account URL is set");
- goto error;
- }
-
- if (priv_is_tel_num (sipuri))
- {
- user = priv_strip_tel_num (sipuri);
- }
- else
- {
- user = g_uri_escape_string (sipuri,
- TPSIP_RESERVED_CHARS_ALLOWED_IN_USERNAME, FALSE);
- }
-
- if (base_url->url_type == url_sips)
- url = url_format (home, "sips:%s@%s",
- user, base_url->url_host);
- else
- url = url_format (home, "sip:%s@%s",
- user, base_url->url_host);
-
- g_free (user);
-
- if (!url) goto error;
- }
- else if (url->url_scheme == NULL)
- {
- /* Set the scheme to SIP or SIPS accordingly to the connection's
- * transport preference */
- if (transport != NULL
- && g_ascii_strcasecmp (transport, "tls") == 0)
- {
- url->url_type = url_sips;
- url->url_scheme = "sips";
- }
- else
- {
- url->url_type = url_sip;
- url->url_scheme = "sip";
- }
- }
-
- if (url_sanitize (url) != 0) goto error;
-
- /* scheme should've been set by now */
- if (url->url_scheme == NULL || (url->url_scheme[0] == 0))
- goto error;
-
- /* convert the scheme to lowercase */
- /* Note: we can't do it in place because url->url_scheme may point to
- * a static string */
- url->url_scheme = priv_lowercase_url_part (home, url->url_scheme);
-
- /* Check that if we have '@', the username isn't empty.
- * Note that we rely on Sofia-SIP to canonize the user name */
- if (url->url_user)
- {
- if (url->url_user[0] == 0) goto error;
- }
-
- /* host should be set and valid */
- if (url->url_host == NULL || !priv_is_host (url->url_host))
- goto error;
-
- /* convert host to lowercase */
- for (c = (char *) url->url_host; *c; c++)
- {
- *c = g_ascii_tolower (*c);
- }
-
- retval = g_strdup (url_as_string (home, url));
-
-error:
- if (retval == NULL)
- g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_HANDLE,
- "invalid SIP URI");
-
- su_home_deinit (home);
- return retval;
-}
-
gchar *
tpsip_handle_normalize (TpHandleRepoIface *repo,
const gchar *sipuri,
diff --git a/tpsip/Makefile.am b/tpsip/Makefile.am
index d675b98..6312f83 100644
--- a/tpsip/Makefile.am
+++ b/tpsip/Makefile.am
@@ -20,6 +20,7 @@ tpsip_include_HEADERS = \
sofia-decls.h \
codec-param-formats.h \
event-target.h \
+ handles.h \
util.h
BUILT_SOURCES = \
@@ -30,6 +31,7 @@ libtpsip_la_SOURCES = \
base-connection.c \
codec-param-formats.c \
event-target.c \
+ handles.c \
util.c
nodist_libtpsip_la_SOURCES = \
diff --git a/tpsip/handles.c b/tpsip/handles.c
new file mode 100644
index 0000000..55eb7e2
--- /dev/null
+++ b/tpsip/handles.c
@@ -0,0 +1,345 @@
+/*
+ * tpsip/handles.c - Handler helpers
+ * Copyright (C) 2005 Collabora Ltd.
+ * Copyright (C) 2006-2011 Nokia Corporation
+ *
+ * This work is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this work; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <tpsip/handles.h>
+#include <sofia-sip/sip_header.h>
+
+#define DEBUG_FLAG TPSIP_DEBUG_CONNECTION
+#include "src/debug.h"
+
+static GQuark
+tpsip_handle_url_quark ()
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ quark = g_quark_from_static_string ("tpsip-handle-url");
+
+ return quark;
+}
+
+const url_t*
+tpsip_handle_inspect_uri (TpBaseConnection *base,
+ TpHandle handle)
+{
+ TpHandleRepoIface *repo;
+ GQuark url_quark;
+ url_t *url;
+ GError *error;
+
+ repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT);
+
+ if (!tp_handle_is_valid (repo, handle, &error))
+ {
+ DEBUG("invalid handle %u: %s", handle, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ url_quark = tpsip_handle_url_quark ();
+
+ url = tp_handle_get_qdata (repo, handle, url_quark);
+
+ if (url == NULL)
+ {
+ url = url_make (NULL, tp_handle_inspect (repo, handle));
+
+ tp_handle_set_qdata (repo, handle, url_quark, url, free);
+ }
+
+ return url;
+}
+
+TpHandle
+tpsip_handle_ensure (TpBaseConnection *conn,
+ url_t const *uri,
+ char const *alias)
+{
+ TpHandleRepoIface *repo;
+ gchar *str;
+ TpHandle handle;
+
+ g_return_val_if_fail (TP_IS_BASE_CONNECTION (conn), 0);
+ g_return_val_if_fail (uri != NULL, 0);
+
+ repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+
+ str = url_as_string (NULL, uri);
+
+ handle = tp_handle_ensure (repo, str, NULL, NULL);
+
+ su_free (NULL, str);
+
+ /* TODO: set qdata for the alias */
+
+ return handle;
+}
+
+TpHandle
+tpsip_handle_by_requestor (TpBaseConnection *conn,
+ sip_t const *sip)
+{
+ url_t const *uri;
+ char const *display;
+
+ g_return_val_if_fail (sip != NULL, 0);
+ g_return_val_if_fail (sip->sip_from != NULL, 0);
+
+ uri = sip->sip_from->a_url;
+ display = sip->sip_from->a_display;
+
+ return tpsip_handle_ensure (conn, uri, display);
+}
+
+void
+tpsip_handle_unref (TpBaseConnection *conn,
+ TpHandle handle)
+{
+ TpHandleRepoIface *repo;
+
+ g_return_if_fail (TP_IS_BASE_CONNECTION (conn));
+ g_return_if_fail (handle != 0);
+
+ repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+
+ tp_handle_unref (repo, handle);
+}
+
+char const *
+tpsip_handle_inspect (TpBaseConnection *conn,
+ TpHandle handle)
+{
+ TpHandleRepoIface *repo;
+
+ g_return_val_if_fail (TP_IS_BASE_CONNECTION (conn), NULL);
+ g_return_val_if_fail (handle != 0, NULL);
+
+ repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+
+ return tp_handle_inspect (repo, handle);
+}
+
+static gboolean
+priv_is_host (const gchar* str)
+{
+ static GRegex *host_regex = NULL;
+
+#define DOMAIN "[a-z0-9]([-a-z0-9]*[a-z0-9])?"
+#define TLD "[a-z]([-a-z0-9]*[a-z0-9])?"
+
+ if (host_regex == NULL)
+ {
+ GError *error = NULL;
+
+ host_regex = g_regex_new ("^("
+ "("DOMAIN"\\.)*"TLD"\\.?|" /* host name */
+ "[0-9]{1,3}(\\.[0-9]{1,3}){3}|" /* IPv4 address */
+ "\\[[0-9a-f:.]\\]" /* IPv6 address, sloppily */
+ ")$",
+ G_REGEX_CASELESS | G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
+
+ if (error != NULL)
+ g_error ("failed to compile the host regex: %s", error->message);
+ }
+
+#undef DOMAIN
+#undef TLD
+
+ return g_regex_match (host_regex, str, 0, NULL);
+}
+
+static gboolean
+priv_is_tel_num (const gchar *str)
+{
+ static GRegex *tel_num_regex = NULL;
+
+ if (tel_num_regex == NULL)
+ {
+ GError *error = NULL;
+
+ tel_num_regex = g_regex_new (
+ "^\\s*[\\+(]?\\s*[0-9][-.0-9()\\s]*$",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
+
+ if (error != NULL)
+ g_error ("failed to compile the telephone number regex: %s",
+ error->message);
+ }
+
+ return g_regex_match (tel_num_regex, str, 0, NULL);
+}
+
+/* Strip the non-essential characters from a string regarded as
+ * a telephone number */
+static gchar *
+priv_strip_tel_num (const gchar *fuzzy)
+{
+ static GRegex *cruft_regex = NULL;
+
+ if (cruft_regex == NULL)
+ {
+ GError *error = NULL;
+
+ cruft_regex = g_regex_new ("[^+0-9]+",
+ G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &error);
+
+ if (error != NULL)
+ g_error ("failed to compile the non-essential "
+ "telephone number cruft regex: %s", error->message);
+ }
+
+ return g_regex_replace_literal (cruft_regex, fuzzy, -1, 0, "", 0, NULL);
+}
+
+static const char *
+priv_lowercase_url_part (su_home_t *home, const char *src)
+{
+ size_t n = 0;
+ size_t i;
+ char *res;
+
+ for (i = 0; src[i]; i++)
+ {
+ if (g_ascii_isupper (src[i]))
+ {
+ n = i + strlen (src + i);
+ break;
+ }
+ }
+
+ if (!src[i])
+ return src;
+
+ res = su_alloc (home, n + 1);
+ memcpy (res, src, i);
+ for (; i < n; i++)
+ res[i] = g_ascii_tolower (src[i]);
+ res[i] = '\0';
+
+ return (const char *) res;
+}
+
+#define TPSIP_RESERVED_CHARS_ALLOWED_IN_USERNAME "!*'()&=+$,;?/"
+
+gchar *
+tpsip_normalize_contact (const gchar *sipuri,
+ const url_t *base_url,
+ const gchar *transport,
+ GError **error)
+{
+ su_home_t home[1] = { SU_HOME_INIT(home) };
+ url_t *url;
+ gchar *retval = NULL;
+ char *c;
+
+ url = url_make (home, sipuri);
+
+ if (url == NULL ||
+ (url->url_scheme == NULL && url->url_user == NULL))
+ {
+ /* we got username or phone number, local to our domain */
+ gchar *user;
+
+ if (base_url == NULL || base_url->url_host == NULL)
+ {
+ WARNING ("bare name given, but no account URL is set");
+ goto error;
+ }
+
+ if (priv_is_tel_num (sipuri))
+ {
+ user = priv_strip_tel_num (sipuri);
+ }
+ else
+ {
+ user = g_uri_escape_string (sipuri,
+ TPSIP_RESERVED_CHARS_ALLOWED_IN_USERNAME, FALSE);
+ }
+
+ if (base_url->url_type == url_sips)
+ url = url_format (home, "sips:%s@%s",
+ user, base_url->url_host);
+ else
+ url = url_format (home, "sip:%s@%s",
+ user, base_url->url_host);
+
+ g_free (user);
+
+ if (!url) goto error;
+ }
+ else if (url->url_scheme == NULL)
+ {
+ /* Set the scheme to SIP or SIPS accordingly to the connection's
+ * transport preference */
+ if (transport != NULL
+ && g_ascii_strcasecmp (transport, "tls") == 0)
+ {
+ url->url_type = url_sips;
+ url->url_scheme = "sips";
+ }
+ else
+ {
+ url->url_type = url_sip;
+ url->url_scheme = "sip";
+ }
+ }
+
+ if (url_sanitize (url) != 0) goto error;
+
+ /* scheme should've been set by now */
+ if (url->url_scheme == NULL || (url->url_scheme[0] == 0))
+ goto error;
+
+ /* convert the scheme to lowercase */
+ /* Note: we can't do it in place because url->url_scheme may point to
+ * a static string */
+ url->url_scheme = priv_lowercase_url_part (home, url->url_scheme);
+
+ /* Check that if we have '@', the username isn't empty.
+ * Note that we rely on Sofia-SIP to canonize the user name */
+ if (url->url_user)
+ {
+ if (url->url_user[0] == 0) goto error;
+ }
+
+ /* host should be set and valid */
+ if (url->url_host == NULL || !priv_is_host (url->url_host))
+ goto error;
+
+ /* convert host to lowercase */
+ for (c = (char *) url->url_host; *c; c++)
+ {
+ *c = g_ascii_tolower (*c);
+ }
+
+ retval = g_strdup (url_as_string (home, url));
+
+error:
+ if (retval == NULL)
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_HANDLE,
+ "invalid SIP URI");
+
+ su_home_deinit (home);
+ return retval;
+}
diff --git a/tpsip/handles.h b/tpsip/handles.h
new file mode 100644
index 0000000..53dbf93
--- /dev/null
+++ b/tpsip/handles.h
@@ -0,0 +1,47 @@
+/*
+ * tpsip/handle.h - Telepathy SIP handle management
+ * Copyright (C) 2011 Nokia Corporation
+ * @author Pekka Pessi <pekka.pessi@nokia.com>
+ *
+ * This work is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this work; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TPSIP_HANDLE_H
+#define TPSIP_HANDLE_H
+
+#include <telepathy-glib/base-connection.h>
+#include <sofia-sip/sip.h>
+
+G_BEGIN_DECLS
+
+TpHandle tpsip_handle_ensure (TpBaseConnection *, url_t const *, char const *);
+TpHandle tpsip_handle_by_requestor (TpBaseConnection *, sip_t const *sip);
+void tpsip_handle_unref (TpBaseConnection *, TpHandle handle);
+char const *tpsip_handle_inspect (TpBaseConnection *, TpHandle handle);
+const url_t *tpsip_handle_inspect_uri (TpBaseConnection *, TpHandle handle);
+
+gchar * tpsip_handle_normalize (TpHandleRepoIface *repo,
+ const gchar *sipuri,
+ gpointer context,
+ GError **error);
+
+gchar *tpsip_normalize_contact (const gchar *sipuri,
+ const url_t *base_url,
+ const gchar *transport,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* !TPSIP_HANDLE_H */