2011-05-22 12:44:34 +02:00
|
|
|
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
|
2011-03-02 21:39:32 +01:00
|
|
|
/*
|
2016-02-21 18:48:21 +01:00
|
|
|
** Copyright (C) 2008-2016 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
2011-03-02 21:39:32 +01:00
|
|
|
**
|
|
|
|
** This program is free software; you can redistribute it and/or modify it
|
|
|
|
** under the terms of the GNU General Public License as published by the
|
|
|
|
** Free Software Foundation; either version 3, 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 General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU General Public License
|
|
|
|
** along with this program; if not, write to the Free Software Foundation,
|
|
|
|
** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2011-05-24 20:41:52 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
#include "mu-contacts.h"
|
|
|
|
#include "mu-util.h"
|
2011-03-03 20:22:11 +01:00
|
|
|
#include "mu-str.h"
|
2011-03-02 21:39:32 +01:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
#define EMAIL_KEY "email"
|
|
|
|
#define NAME_KEY "name"
|
|
|
|
#define TSTAMP_KEY "tstamp"
|
2012-06-18 16:59:27 +02:00
|
|
|
#define PERSONAL_KEY "personal"
|
2013-06-16 12:14:39 +02:00
|
|
|
#define FREQ_KEY "frequency"
|
2012-06-18 16:59:27 +02:00
|
|
|
|
|
|
|
/* note: 'personal' here means a mail where my e-mail addresses is explicitly
|
|
|
|
* in one of the address fields, ie., it's not some mailing list message */
|
2011-03-02 21:39:32 +01:00
|
|
|
struct _ContactInfo {
|
2013-06-16 12:14:39 +02:00
|
|
|
gchar *_name, *_email;
|
|
|
|
gboolean _personal;
|
|
|
|
time_t _tstamp;
|
|
|
|
unsigned _freq;
|
2011-03-02 21:39:32 +01:00
|
|
|
};
|
|
|
|
typedef struct _ContactInfo ContactInfo;
|
|
|
|
|
|
|
|
static void contact_info_destroy (ContactInfo *cinfo);
|
2011-05-24 20:41:52 +02:00
|
|
|
static ContactInfo *contact_info_new (char *email, char *name,
|
2013-06-16 12:14:39 +02:00
|
|
|
gboolean personal, time_t tstamp, unsigned freq);
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
struct _MuContacts {
|
2016-12-11 17:33:31 +01:00
|
|
|
GKeyFile *_ccache;
|
2013-06-16 12:14:39 +02:00
|
|
|
gchar *_path;
|
2011-05-24 20:41:52 +02:00
|
|
|
|
2013-06-16 12:14:39 +02:00
|
|
|
GHashTable *_hash;
|
|
|
|
gboolean _dirty;
|
2011-03-02 21:39:32 +01:00
|
|
|
};
|
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
static GKeyFile*
|
|
|
|
load_key_file (const char *path)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2013-06-16 12:14:39 +02:00
|
|
|
GError *err;
|
|
|
|
GKeyFile *keyfile;
|
|
|
|
gboolean file_exists;
|
2011-03-02 21:39:32 +01:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
err = NULL;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
/* of course this is racy, but it's only for giving more
|
|
|
|
* meaningful errors to users */
|
|
|
|
file_exists = TRUE;
|
|
|
|
if (access(path, F_OK) != 0) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
g_warning ("cannot open %s: %s", path, strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
file_exists = FALSE;
|
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
err = NULL;
|
2011-05-24 20:41:52 +02:00
|
|
|
keyfile = g_key_file_new ();
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
if (file_exists && !g_key_file_load_from_file
|
|
|
|
(keyfile, path, G_KEY_FILE_KEEP_COMMENTS, &err)) {
|
|
|
|
g_warning ("could not load keyfile %s: %s", path, err->message);
|
2011-03-02 21:39:32 +01:00
|
|
|
g_error_free (err);
|
2011-05-24 20:41:52 +02:00
|
|
|
g_key_file_free (keyfile);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return keyfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
get_values (GKeyFile *kfile, const gchar *group,
|
2013-06-16 12:14:39 +02:00
|
|
|
gchar **email, gchar **name, gboolean *personal, size_t *tstamp,
|
|
|
|
unsigned *freq)
|
2011-05-24 20:41:52 +02:00
|
|
|
{
|
|
|
|
GError *err;
|
|
|
|
err = NULL;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
do {
|
2013-06-16 12:14:39 +02:00
|
|
|
int i;
|
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
*email = g_key_file_get_value (kfile, group, EMAIL_KEY, &err);
|
|
|
|
if (!*email)
|
|
|
|
break;
|
|
|
|
|
2012-10-22 22:15:28 +02:00
|
|
|
*tstamp = (time_t)g_key_file_get_integer (kfile, group,
|
|
|
|
TSTAMP_KEY, &err);
|
2011-05-24 20:41:52 +02:00
|
|
|
if (err)
|
2012-06-18 16:59:27 +02:00
|
|
|
break;
|
2012-10-22 22:15:28 +02:00
|
|
|
*personal = g_key_file_get_boolean (kfile, group,
|
|
|
|
PERSONAL_KEY, NULL);
|
2012-06-18 16:59:27 +02:00
|
|
|
*name = g_key_file_get_value (kfile, group, NAME_KEY, NULL);
|
2011-05-24 20:41:52 +02:00
|
|
|
|
2013-06-16 12:14:39 +02:00
|
|
|
i = g_key_file_get_integer (kfile, group, FREQ_KEY, NULL);
|
|
|
|
*freq = (unsigned)(i >= 0) ? i : 1;
|
2012-10-22 22:15:28 +02:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
g_warning ("error getting value for %s: %s",
|
|
|
|
group, err->message ? err->message: "error");
|
|
|
|
g_clear_error (&err);
|
|
|
|
|
|
|
|
return FALSE;
|
2011-05-24 20:41:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
deserialize_cache (MuContacts *self)
|
|
|
|
{
|
|
|
|
gchar **groups;
|
|
|
|
gsize i, len;
|
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
groups = g_key_file_get_groups (self->_ccache, &len);
|
2011-05-24 20:41:52 +02:00
|
|
|
for (i = 0; i != len; ++i) {
|
2011-03-02 21:39:32 +01:00
|
|
|
ContactInfo *cinfo;
|
2011-05-24 20:41:52 +02:00
|
|
|
char *name, *email;
|
|
|
|
size_t tstamp;
|
2012-06-18 16:59:27 +02:00
|
|
|
gboolean personal;
|
2013-06-16 12:14:39 +02:00
|
|
|
unsigned freq;
|
2011-05-24 20:41:52 +02:00
|
|
|
if (!get_values (self->_ccache, groups[i],
|
2013-06-16 12:14:39 +02:00
|
|
|
&email, &name, &personal, &tstamp, &freq))
|
2011-05-24 20:41:52 +02:00
|
|
|
continue; /* ignore this one... */
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2013-06-16 12:14:39 +02:00
|
|
|
cinfo = contact_info_new (email, name, personal, tstamp, freq);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
/* note, we're using the groups[i], so don't free with g_strfreev */
|
2011-05-24 20:41:52 +02:00
|
|
|
g_hash_table_insert (self->_hash, groups[i],
|
|
|
|
cinfo);
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
g_free (groups);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
static gboolean
|
|
|
|
set_comment (GKeyFile *kfile)
|
|
|
|
{
|
|
|
|
GError *err;
|
|
|
|
const char *comment =
|
|
|
|
" automatically generated -- do not edit";
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
err = NULL;
|
|
|
|
if (!g_key_file_set_comment (kfile, NULL, NULL, comment, &err)) {
|
|
|
|
g_warning ("could not write comment to keyfile: %s",
|
|
|
|
err->message);
|
|
|
|
g_error_free (err);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
MuContacts*
|
2011-08-30 21:00:00 +02:00
|
|
|
mu_contacts_new (const gchar *path)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2011-05-24 20:41:52 +02:00
|
|
|
MuContacts *self;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
|
|
|
g_return_val_if_fail (path, NULL);
|
2011-05-24 20:41:52 +02:00
|
|
|
self = g_new0 (MuContacts, 1);
|
2011-03-02 21:39:32 +01:00
|
|
|
|
2011-08-30 21:00:00 +02:00
|
|
|
self->_path = g_strdup (path);
|
2011-05-24 20:41:52 +02:00
|
|
|
self->_hash = g_hash_table_new_full
|
|
|
|
(g_str_hash, g_str_equal, g_free,
|
|
|
|
(GDestroyNotify)contact_info_destroy);
|
|
|
|
|
2011-08-30 21:00:00 +02:00
|
|
|
self->_ccache = load_key_file (path);
|
|
|
|
if (!self->_ccache || !set_comment (self->_ccache)) {
|
|
|
|
mu_contacts_destroy (self);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-05-24 20:41:52 +02:00
|
|
|
deserialize_cache (self);
|
|
|
|
MU_WRITE_LOG("deserialized contacts from cache %s",
|
2011-08-30 21:00:00 +02:00
|
|
|
path);
|
|
|
|
|
|
|
|
self->_dirty = FALSE;
|
2011-05-24 20:41:52 +02:00
|
|
|
return self;
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-30 21:00:00 +02:00
|
|
|
void
|
|
|
|
mu_contacts_clear (MuContacts *self)
|
|
|
|
{
|
|
|
|
g_return_if_fail (self);
|
|
|
|
|
|
|
|
if (self->_ccache)
|
|
|
|
g_key_file_free (self->_ccache);
|
|
|
|
|
|
|
|
g_hash_table_remove_all (self->_hash);
|
|
|
|
|
|
|
|
self->_ccache = g_key_file_new ();
|
|
|
|
self->_dirty = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-24 22:47:47 +02:00
|
|
|
/*
|
|
|
|
* we use the e-mail address to create a key in the GKeyFile, but we
|
|
|
|
* have to mutilate a bit so that it's (a) *cough* practically-unique
|
|
|
|
* and (b) valid as a GKeyFile group name (ie., valid utf8, no control
|
|
|
|
* chars, no '[' or ']')
|
|
|
|
*/
|
|
|
|
static const char*
|
|
|
|
encode_email_address (const char *addr)
|
|
|
|
{
|
|
|
|
static char enc[254 + 1]; /* max size for an e-mail addr */
|
|
|
|
char *cur;
|
|
|
|
|
|
|
|
if (!addr)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* make sure chars are with {' ' .. '~'}, and not '[' ']' */
|
|
|
|
for (cur = strncpy(enc, addr, sizeof(enc)); *cur != '\0'; ++cur)
|
|
|
|
if (!isalnum(*cur)) {
|
|
|
|
*cur = 'A' + (*cur % ('Z' - 'A'));
|
|
|
|
} else
|
|
|
|
*cur = tolower(*cur);
|
|
|
|
|
|
|
|
return enc;
|
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2013-04-07 15:03:25 +02:00
|
|
|
|
|
|
|
/* downcase the domain-part of the email address, but only if it
|
|
|
|
* consists of ascii (to prevent screwing up idna addresses)
|
|
|
|
*/
|
2016-12-11 17:33:31 +01:00
|
|
|
static char*
|
2013-04-07 15:03:25 +02:00
|
|
|
downcase_domain_maybe (const char *addr)
|
|
|
|
{
|
|
|
|
char *addr_conv, *at, *cur;
|
|
|
|
|
|
|
|
addr_conv = g_strdup (addr);
|
|
|
|
|
|
|
|
if (!(at = strchr (addr_conv, '@'))) { /*huh?*/
|
|
|
|
g_free (addr_conv);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cur = at + 1; *cur; ++cur) {
|
|
|
|
if (isascii(*cur))
|
|
|
|
*cur = g_ascii_tolower (*cur);
|
|
|
|
else { /* non-ascii; return the unchanged original */
|
|
|
|
g_free (addr_conv);
|
|
|
|
return g_strdup (addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr_conv;
|
|
|
|
}
|
|
|
|
|
2013-06-24 21:42:18 +02:00
|
|
|
static void
|
|
|
|
clear_str (char* str)
|
|
|
|
{
|
|
|
|
if (str) {
|
|
|
|
mu_str_remove_ctrl_in_place (str);
|
|
|
|
g_strstrip (str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
gboolean
|
2012-10-24 22:47:47 +02:00
|
|
|
mu_contacts_add (MuContacts *self, const char *addr, const char *name,
|
2012-06-18 16:59:27 +02:00
|
|
|
gboolean personal, time_t tstamp)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2015-12-30 14:33:27 +01:00
|
|
|
ContactInfo *cinfo;
|
|
|
|
const char *group;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
g_return_val_if_fail (self, FALSE);
|
2012-10-24 22:47:47 +02:00
|
|
|
g_return_val_if_fail (addr, FALSE);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2015-12-30 14:33:27 +01:00
|
|
|
group = encode_email_address (addr);
|
2016-12-11 17:33:31 +01:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
cinfo = (ContactInfo*) g_hash_table_lookup (self->_hash, group);
|
2013-06-16 12:14:39 +02:00
|
|
|
if (!cinfo) {
|
2013-04-07 15:03:25 +02:00
|
|
|
char *addr_dc;
|
|
|
|
if (!(addr_dc = downcase_domain_maybe (addr)))
|
|
|
|
return FALSE;
|
2013-06-16 12:14:39 +02:00
|
|
|
cinfo = contact_info_new (addr_dc,
|
|
|
|
name ? g_strdup(name) : NULL, personal,
|
|
|
|
tstamp, 1);
|
|
|
|
g_hash_table_insert (self->_hash, g_strdup(group), cinfo);
|
|
|
|
} else {
|
2016-02-21 18:48:21 +01:00
|
|
|
/* if the contact is ever used in a personal way, it's
|
2015-12-30 14:33:27 +01:00
|
|
|
* personal */
|
|
|
|
if (personal)
|
|
|
|
cinfo->_personal = TRUE;
|
2016-12-11 17:33:31 +01:00
|
|
|
|
2013-06-16 12:14:39 +02:00
|
|
|
if (cinfo->_tstamp < tstamp) {
|
|
|
|
if (!mu_str_is_empty(name)) {
|
|
|
|
/* update the name to the last one used, unless it's
|
|
|
|
* empty*/
|
|
|
|
g_free (cinfo->_name);
|
|
|
|
cinfo->_name = g_strdup (name);
|
2013-06-24 21:42:18 +02:00
|
|
|
if (cinfo->_name)
|
|
|
|
mu_str_remove_ctrl_in_place (cinfo->_name);
|
2013-06-16 12:14:39 +02:00
|
|
|
}
|
|
|
|
cinfo->_tstamp = tstamp;
|
|
|
|
}
|
|
|
|
++cinfo->_freq;
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2013-06-16 12:14:39 +02:00
|
|
|
|
|
|
|
self->_dirty = TRUE;
|
|
|
|
|
|
|
|
return TRUE;
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
struct _EachContactData {
|
|
|
|
MuContactsForeachFunc _func;
|
|
|
|
gpointer _user_data;
|
2011-03-03 20:22:11 +01:00
|
|
|
GRegex *_rx;
|
2011-03-05 14:07:49 +01:00
|
|
|
size_t _num;
|
2011-03-02 21:39:32 +01:00
|
|
|
};
|
|
|
|
typedef struct _EachContactData EachContactData;
|
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
static void /* email will never be NULL, but ci->_name may be */
|
2011-05-24 20:41:52 +02:00
|
|
|
each_contact (const char *group, ContactInfo *ci, EachContactData *ecdata)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2011-05-24 20:41:52 +02:00
|
|
|
if (!ci->_email)
|
|
|
|
g_warning ("missing email: %u", (unsigned)ci->_tstamp);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
/* ignore this contact if we have a regexp, and it matches
|
2011-05-18 18:19:08 +02:00
|
|
|
* neither email nor name (if we have a name) */
|
2011-03-03 20:22:11 +01:00
|
|
|
while (ecdata->_rx) { /* note, only once */
|
2011-05-24 20:41:52 +02:00
|
|
|
if (g_regex_match (ecdata->_rx, ci->_email, 0, NULL))
|
2011-03-03 20:22:11 +01:00
|
|
|
break; /* email matches? continue! */
|
|
|
|
if (!ci->_name)
|
|
|
|
return; /* email did not match, no name? ignore this one */
|
2011-05-18 18:19:08 +02:00
|
|
|
if (g_regex_match (ecdata->_rx, ci->_name, 0, NULL))
|
2011-03-03 20:22:11 +01:00
|
|
|
break; /* name matches? continue! */
|
|
|
|
return; /* nothing matched, ignore this one */
|
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
ecdata->_func (ci->_email, ci->_name, ci->_personal,
|
2013-06-16 22:02:19 +02:00
|
|
|
ci->_tstamp, ci->_freq, ecdata->_user_data);
|
2012-06-18 16:59:27 +02:00
|
|
|
|
2011-03-05 14:07:49 +01:00
|
|
|
++ecdata->_num;
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
gboolean
|
2011-03-02 21:39:32 +01:00
|
|
|
mu_contacts_foreach (MuContacts *self, MuContactsForeachFunc func,
|
2011-03-05 14:07:49 +01:00
|
|
|
gpointer user_data, const char *pattern, size_t *num)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
|
|
|
EachContactData ecdata;
|
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
g_return_val_if_fail (self, FALSE);
|
|
|
|
g_return_val_if_fail (func, FALSE);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
if (pattern) {
|
|
|
|
GError *err;
|
|
|
|
err = NULL;
|
|
|
|
ecdata._rx = g_regex_new
|
2011-05-05 21:53:04 +02:00
|
|
|
(pattern, G_REGEX_CASELESS|G_REGEX_OPTIMIZE,
|
2011-03-03 20:22:11 +01:00
|
|
|
0, &err);
|
|
|
|
if (!ecdata._rx) {
|
2011-05-05 21:53:04 +02:00
|
|
|
g_warning ("error in regexp '%s': %s",
|
|
|
|
pattern, err->message);
|
2011-03-03 20:22:11 +01:00
|
|
|
g_error_free (err);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
ecdata._rx = NULL;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
ecdata._func = func;
|
|
|
|
ecdata._user_data = user_data;
|
2011-03-05 14:07:49 +01:00
|
|
|
ecdata._num = 0;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
g_hash_table_foreach (self->_hash,
|
|
|
|
(GHFunc)each_contact,
|
|
|
|
&ecdata);
|
2011-03-03 20:22:11 +01:00
|
|
|
|
|
|
|
if (ecdata._rx)
|
|
|
|
g_regex_unref (ecdata._rx);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-05 14:07:49 +01:00
|
|
|
if (num)
|
|
|
|
*num = ecdata._num;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-03-03 20:22:11 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
static void
|
2011-05-24 20:41:52 +02:00
|
|
|
each_keyval (const char *group, ContactInfo *cinfo, MuContacts *self)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2011-05-24 20:41:52 +02:00
|
|
|
/* use set value so the string do not necessarily have to be
|
|
|
|
* valid utf-8 */
|
2011-03-02 21:39:32 +01:00
|
|
|
if (cinfo->_name)
|
2011-05-24 20:41:52 +02:00
|
|
|
g_key_file_set_value (self->_ccache, group, NAME_KEY,
|
2011-03-02 21:39:32 +01:00
|
|
|
cinfo->_name);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-24 20:41:52 +02:00
|
|
|
g_key_file_set_value (self->_ccache, group, EMAIL_KEY,
|
|
|
|
cinfo->_email);
|
2012-06-18 16:59:27 +02:00
|
|
|
g_key_file_set_boolean (self->_ccache, group, PERSONAL_KEY,
|
|
|
|
cinfo->_personal);
|
2011-05-24 20:41:52 +02:00
|
|
|
g_key_file_set_integer (self->_ccache, group, TSTAMP_KEY,
|
2011-05-04 00:43:01 +02:00
|
|
|
(int)cinfo->_tstamp);
|
2013-06-16 12:14:39 +02:00
|
|
|
g_key_file_set_integer (self->_ccache, group, FREQ_KEY,
|
|
|
|
(int)cinfo->_freq);
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
|
|
|
|
2016-02-21 18:48:21 +01:00
|
|
|
gboolean
|
|
|
|
mu_contacts_serialize (MuContacts *self)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
2016-02-21 18:48:21 +01:00
|
|
|
gchar *data;
|
|
|
|
gsize len;
|
|
|
|
gboolean rv;
|
|
|
|
|
|
|
|
g_return_val_if_fail (self, FALSE);
|
2011-03-02 21:39:32 +01:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
g_hash_table_foreach (self->_hash, (GHFunc)each_keyval, self);
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
/* Note: err arg is unused */
|
2016-02-21 18:48:21 +01:00
|
|
|
data = g_key_file_to_data (self->_ccache, &len, NULL);
|
2011-03-02 21:39:32 +01:00
|
|
|
if (len) {
|
2016-02-21 18:48:21 +01:00
|
|
|
GError *err;
|
2011-03-02 21:39:32 +01:00
|
|
|
err = NULL;
|
2016-02-21 18:48:21 +01:00
|
|
|
rv = g_file_set_contents (self->_path, data, len, &err);
|
2011-03-02 21:39:32 +01:00
|
|
|
if (!rv) {
|
|
|
|
g_warning ("failed to serialize cache to %s: %s",
|
2011-08-30 21:00:00 +02:00
|
|
|
self->_path, err->message);
|
2011-03-02 21:39:32 +01:00
|
|
|
g_error_free (err);
|
|
|
|
}
|
|
|
|
g_free (data);
|
2013-05-20 04:15:11 +02:00
|
|
|
} else
|
|
|
|
rv = TRUE;
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mu_contacts_destroy (MuContacts *self)
|
|
|
|
{
|
|
|
|
if (!self)
|
|
|
|
return;
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2016-02-21 18:48:21 +01:00
|
|
|
if (self->_ccache && self->_dirty &&
|
|
|
|
mu_contacts_serialize (self))
|
2011-03-02 21:39:32 +01:00
|
|
|
MU_WRITE_LOG("serialized contacts cache %s",
|
2011-08-30 21:00:00 +02:00
|
|
|
self->_path);
|
2016-12-11 17:33:31 +01:00
|
|
|
|
2011-03-06 11:16:04 +01:00
|
|
|
if (self->_ccache)
|
|
|
|
g_key_file_free (self->_ccache);
|
|
|
|
|
2011-08-30 21:00:00 +02:00
|
|
|
g_free (self->_path);
|
|
|
|
|
2011-03-02 21:39:32 +01:00
|
|
|
if (self->_hash)
|
|
|
|
g_hash_table_destroy (self->_hash);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
|
|
|
g_free (self);
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
|
|
|
|
2016-02-21 18:48:21 +01:00
|
|
|
/* note, we will *own* the name, email we get, and we'll free them in the
|
|
|
|
* end... */
|
2011-03-02 21:39:32 +01:00
|
|
|
static ContactInfo *
|
2013-06-16 12:14:39 +02:00
|
|
|
contact_info_new (char *email, char *name, gboolean personal, time_t tstamp,
|
|
|
|
unsigned freq)
|
2011-03-02 21:39:32 +01:00
|
|
|
{
|
|
|
|
ContactInfo *cinfo;
|
2011-05-24 20:41:52 +02:00
|
|
|
|
|
|
|
/* email should not be NULL, name can */
|
|
|
|
g_return_val_if_fail (email, NULL);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2011-05-25 07:11:50 +02:00
|
|
|
cinfo = g_slice_new (ContactInfo);
|
2011-05-24 20:41:52 +02:00
|
|
|
|
2011-05-24 22:21:51 +02:00
|
|
|
/* we need to clear the strings from control chars because
|
|
|
|
* they could screw up the keyfile */
|
2011-05-24 20:41:52 +02:00
|
|
|
clear_str (email);
|
|
|
|
clear_str (name);
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
cinfo->_email = email;
|
|
|
|
cinfo->_name = name;
|
|
|
|
cinfo->_personal = personal;
|
|
|
|
cinfo->_tstamp = tstamp;
|
2013-06-16 12:14:39 +02:00
|
|
|
cinfo->_freq = freq;
|
2011-03-02 21:39:32 +01:00
|
|
|
|
|
|
|
return cinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
contact_info_destroy (ContactInfo *cinfo)
|
|
|
|
{
|
2011-05-04 00:43:01 +02:00
|
|
|
if (!cinfo)
|
|
|
|
return;
|
2011-05-24 20:41:52 +02:00
|
|
|
|
|
|
|
g_free (cinfo->_email);
|
2011-05-04 00:43:01 +02:00
|
|
|
g_free (cinfo->_name);
|
2011-05-24 20:41:52 +02:00
|
|
|
|
2011-05-04 00:43:01 +02:00
|
|
|
g_slice_free (ContactInfo, cinfo);
|
2011-03-02 21:39:32 +01:00
|
|
|
}
|
2011-08-30 21:00:00 +02:00
|
|
|
|
2012-06-18 16:59:27 +02:00
|
|
|
|
|
|
|
size_t
|
|
|
|
mu_contacts_count (MuContacts *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (self, 0);
|
|
|
|
|
|
|
|
return g_hash_table_size (self->_hash);
|
|
|
|
}
|