/*
* gnome-keyring
*
* Copyright (C) 2008 Stefan Walter
*
* This program 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 program 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 program; if not, see
* <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gkd-secret-util.h"
#include "pkcs11/pkcs11i.h"
#include <string.h>
/* -----------------------------------------------------------------------------
* INTERNAL
*/
static gchar*
decode_object_identifier (const gchar* enc, gssize length)
{
GString *result;
g_assert (enc);
if (length < 0)
length = strlen (enc);
result = g_string_sized_new (length);
while (length > 0) {
char ch = *(enc++);
--length;
/* Underscores get special handling */
if (G_UNLIKELY (ch == '_' &&
g_ascii_isxdigit(enc[0]) &&
g_ascii_isxdigit (enc[1]))) {
ch = (g_ascii_xdigit_value (enc[0]) * 16) +
(g_ascii_xdigit_value (enc[1]));
enc += 2;
length -= 2;
}
g_string_append_c (result, ch);
}
return g_string_free (result, FALSE);
}
gboolean
gkd_secret_util_parse_path (const gchar *path, gchar **collection, gchar **item)
{
const gchar *pos;
g_return_val_if_fail (path, FALSE);
/* Make sure it starts with our prefix */
if (g_str_has_prefix (path, SECRET_COLLECTION_PREFIX))
path += strlen (SECRET_COLLECTION_PREFIX);
else if (g_str_has_prefix (path, SECRET_ALIAS_PREFIX))
path += strlen (SECRET_ALIAS_PREFIX);
else
return FALSE;
/* Skip the path separator */
if (path[0] != '/')
return FALSE;
++path;
/* Make sure we have something */
if (path[0] == '\0')
return FALSE;
pos = strchr (path, '/');
/* No item, just a collection */
if (pos == NULL) {
if (collection)
*collection = decode_object_identifier (path, -1);
if (item)
*item = NULL;
return TRUE;
}
/* Make sure we have an item, and no further path bits */
if (pos[1] == '\0' || strchr (pos + 1, '/'))
return FALSE;
if (collection)
*collection = decode_object_identifier (path, pos - path);
if (item)
*item = decode_object_identifier (pos + 1, -1);
return TRUE;
}
gchar*
gkd_secret_util_build_path (const gchar *base, gconstpointer identifier, gssize n_identifier)
{
GString *result;
const gchar *name;
gsize length;
g_assert (base);
g_assert (base[0] == '/');
g_assert (identifier);
name = identifier;
if (n_identifier < 0)
length = strlen (name);
else
length = n_identifier;
result = g_string_new (base);
if (!g_str_has_suffix (base, "/"))
g_string_append_c (result, '/');
while (length > 0) {
char ch = *(name++);
--length;
/* Normal characters can go right through */
if (G_LIKELY ((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch >= '0' && ch <= '9'))) {
g_string_append_c (result, ch);
/* Special characters are encoded with a _ */
} else {
g_string_append_printf (result, "_%02x", (unsigned int)(unsigned char)ch);
}
}
return g_string_free (result, FALSE);
}