Mercurial > hg
view mcabber/src/roster.c @ 100:8fedef290c4e
[/trunk] Changeset 114 by mikael
* Cleaning, add comments, remove debugging stuff...
author | mikael |
---|---|
date | Thu, 21 Apr 2005 17:21:49 +0000 |
parents | c6270994fb6e |
children | d7fbd5293385 |
line wrap: on
line source
/* * roster.c -- Local roster implementation * * Copyright (C) 2005 Mikael Berthe <bmikael@lists.lilotux.net> * * 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 2 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 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include <string.h> #include "roster.h" /* This is a private structure type for the roster */ typedef struct { const char *name; const char *jid; guint type; enum imstatus status; guint flags; // list: user -> points to his group; group -> points to its users list GSList *list; } roster; /* ### Variables ### */ static int hide_offline_buddies; static GSList *groups; GList *buddylist; GList *current_buddy; #ifdef MCABBER_TESTUNIT // Export groups for testing routines GSList **pgroups = &groups; #endif /* ### Roster functions ### */ // Comparison function used to search in the roster (compares jids and types) gint roster_compare_jid_type(roster *a, roster *b) { if (! (a->type & b->type)) return -1; // arbitrary (but should be != , of course) return strcasecmp(a->jid, b->jid); } // Comparison function used to sort the roster (by name) gint roster_compare_name(roster *a, roster *b) { return strcasecmp(a->name, b->name); } // Finds a roster element (user, group, agent...), by jid or name // If roster_type is 0, returns match of any type. // Returns the roster GSList element, or NULL if jid/name not found GSList *roster_find(const char *jidname, enum findwhat type, guint roster_type) { GSList *sl_roster_elt = groups; GSList *res; roster sample; GCompareFunc comp; if (!jidname) return NULL; // should not happen if (!roster_type) roster_type = ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP; sample.type = roster_type; if (type == jidsearch) { sample.jid = jidname; comp = (GCompareFunc)&roster_compare_jid_type; } else if (type == namesearch) { sample.name = jidname; comp = (GCompareFunc)&roster_compare_name; } else return NULL; // should not happen while (sl_roster_elt) { roster *roster_elt = (roster*)sl_roster_elt->data; if (roster_type & ROSTER_TYPE_GROUP) { if ((type == namesearch) && !strcasecmp(jidname, roster_elt->name)) return sl_roster_elt; } else { res = g_slist_find_custom(roster_elt->list, &sample, comp); if (res) return res; } sl_roster_elt = g_slist_next(sl_roster_elt); } return NULL; } // Returns pointer to new group, or existing group with that name GSList *roster_add_group(const char *name) { roster *roster_grp; // #1 Check name doesn't already exist if (!roster_find(name, namesearch, ROSTER_TYPE_GROUP)) { // #2 Create the group node roster_grp = g_new0(roster, 1); roster_grp->name = g_strdup(name); roster_grp->type = ROSTER_TYPE_GROUP; // #3 Insert (sorted) groups = g_slist_insert_sorted(groups, roster_grp, (GCompareFunc)&roster_compare_name); } return roster_find(name, namesearch, ROSTER_TYPE_GROUP); } // Returns a pointer to the new user, or existing user with that name GSList *roster_add_user(const char *jid, const char *name, const char *group, guint type) { roster *roster_usr; roster *my_group; GSList *slist; if ((type != ROSTER_TYPE_USER) && (type != ROSTER_TYPE_AGENT)) { // XXX Error message? return NULL; } // Let's be arbitrary: default group has an empty name (""). if (!group) group = ""; // #1 Check this user doesn't already exist if ((slist = roster_find(jid, jidsearch, type)) != NULL) return slist; // #2 add group if necessary slist = roster_add_group(group); if (!slist) return NULL; my_group = (roster*)slist->data; // #3 Create user node roster_usr = g_new0(roster, 1); roster_usr->jid = g_strdup(jid); if (name) { roster_usr->name = g_strdup(name); } else { gchar *p, *str = g_strdup(jid); p = strstr(str, "/"); if (p) *p = '\0'; roster_usr->name = g_strdup(str); g_free(str); } roster_usr->type = type; //ROSTER_TYPE_USER; roster_usr->list = slist; // (my_group SList element) // #4 Insert node (sorted) my_group->list = g_slist_insert_sorted(my_group->list, roster_usr, (GCompareFunc)&roster_compare_name); return roster_find(jid, jidsearch, type); } // Removes user (jid) from roster, frees allocated memory void roster_del_user(const char *jid) { GSList *sl_user, *sl_group; GSList **sl_group_listptr; roster *roster_usr; sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); if (sl_user == NULL) return; // Let's free memory (jid, name) roster_usr = (roster*)sl_user->data; if (roster_usr->jid) g_free((gchar*)roster_usr->jid); if (roster_usr->name) g_free((gchar*)roster_usr->name); // That's a little complex, we need to dereference twice sl_group = ((roster*)sl_user->data)->list; sl_group_listptr = &((roster*)(sl_group->data))->list; *sl_group_listptr = g_slist_delete_link(*sl_group_listptr, sl_user); // We need to rebuild the list if (current_buddy) buddylist_build(); // TODO What we should do, too, is to check if the deleted node is // current_buddy, in which case we could move current_buddy to the // previous (or next) node. } void roster_setstatus(const char *jid, enum imstatus bstat) { GSList *sl_user; roster *roster_usr; sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); // If we can't find it, we add it if (sl_user == NULL) sl_user = roster_add_user(jid, NULL, NULL, ROSTER_TYPE_USER); roster_usr = (roster*)sl_user->data; roster_usr->status = bstat; } // roster_setflags() // Set one or several flags to value (TRUE/FALSE) void roster_setflags(const char *jid, guint flags, guint value) { GSList *sl_user; roster *roster_usr; sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); if (sl_user == NULL) return; roster_usr = (roster*)sl_user->data; if (value) roster_usr->flags |= flags; else roster_usr->flags &= ~flags; } void roster_settype(const char *jid, guint type) { GSList *sl_user; roster *roster_usr; if ((sl_user = roster_find(jid, jidsearch, 0)) == NULL) return; roster_usr = (roster*)sl_user->data; roster_usr->type = type; } enum imstatus roster_getstatus(const char *jid) { GSList *sl_user; roster *roster_usr; sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); if (sl_user == NULL) return offline; // Not in the roster, anyway... roster_usr = (roster*)sl_user->data; return roster_usr->status; } guint roster_gettype(const char *jid) { GSList *sl_user; roster *roster_usr; if ((sl_user = roster_find(jid, jidsearch, 0)) == NULL) return 0; roster_usr = (roster*)sl_user->data; return roster_usr->type; } // char *roster_getgroup(...) / Or *GSList? Which use?? // ... setgroup(char*) ?? // guchar roster_getflags(...) // guchar roster_getname(...) / setname ?? // roster_del_group? /* ### BuddyList functions ### */ // buddylist_hide_offline_buddies(hide) // "hide" values: 1=hide 0=show_all -1=invert void buddylist_hide_offline_buddies(int hide) { if (hide < 0) // NEG (invert) hide_offline_buddies = !hide_offline_buddies; else if (hide == 0) // FALSE (don't hide) hide_offline_buddies = 0; else // TRUE (hide) hide_offline_buddies = 1; } // buddylist_build() // Creates the buddylist from the roster entries. void buddylist_build(void) { GSList *sl_roster_elt = groups; roster *roster_elt; roster *roster_current_buddy = NULL; int pending_group; // We need to remember which buddy is selected. if (current_buddy) roster_current_buddy = BUDDATA(current_buddy); current_buddy = NULL; // Destroy old buddylist if (buddylist) { g_list_free(buddylist); buddylist = NULL; } // Create the new list while (sl_roster_elt) { GSList *sl_roster_usrelt; roster *roster_usrelt; roster_elt = (roster*) sl_roster_elt->data; // Add the group now unless hide_offline_buddies is set, // in which case we'll add it only if an online buddy belongs to it. if (!hide_offline_buddies) buddylist = g_list_append(buddylist, roster_elt); else pending_group = TRUE; sl_roster_usrelt = roster_elt->list; while (sl_roster_usrelt) { roster_usrelt = (roster*) sl_roster_usrelt->data; // Buddy will be added if either: // - hide_offline_buddies is FALSE // - buddy is not offline // - buddy has a lock (for example the buddy window is currently open) // - buddy has a pending (non-read) message if (!hide_offline_buddies || (buddy_getstatus((gpointer)roster_usrelt) != offline) || (buddy_getflags((gpointer)roster_usrelt) & (ROSTER_FLAG_LOCK | ROSTER_FLAG_MSG))) { // This user should be added. Maybe the group hasn't been added yet? if (hide_offline_buddies && pending_group) { // It hasn't been done yet buddylist = g_list_append(buddylist, roster_elt); pending_group = FALSE; } // Add user buddylist = g_list_append(buddylist, roster_usrelt); } sl_roster_usrelt = g_slist_next(sl_roster_usrelt); } sl_roster_elt = g_slist_next(sl_roster_elt); } // Check if we can find our saved current_buddy... if (roster_current_buddy) current_buddy = g_list_find(buddylist, roster_current_buddy); // current_buddy initialization if (!current_buddy || (g_list_position(buddylist, current_buddy) == -1)) current_buddy = g_list_first(buddylist); } // buddy_hide_group(roster, hide) // "hide" values: 1=hide 0=show_all -1=invert void buddy_hide_group(gpointer rosterdata, int hide) { roster *roster = rosterdata; if (hide > 0) // TRUE (hide) roster->flags |= ROSTER_FLAG_HIDE; else if (hide < 0) // NEG (invert) roster->flags ^= ROSTER_FLAG_HIDE; else // FALSE (don't hide) roster->flags &= ~ROSTER_FLAG_HIDE; } const char *buddy_getjid(gpointer rosterdata) { roster *roster = rosterdata; return roster->jid; } const char *buddy_getname(gpointer rosterdata) { roster *roster = rosterdata; return roster->name; } guint buddy_gettype(gpointer rosterdata) { roster *roster = rosterdata; return roster->type; } enum imstatus buddy_getstatus(gpointer rosterdata) { roster *roster = rosterdata; return roster->status; } guint buddy_getflags(gpointer rosterdata) { roster *roster = rosterdata; return roster->flags; }