--- a/mcabber/src/commands.c Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/commands.c Mon Sep 19 23:32:42 2005 +0200
@@ -627,8 +627,8 @@
jid = buddy_getjid(bud);
name = buddy_getname(bud);
type = buddy_gettype(bud);
- status = buddy_getstatus(bud);
- st_msg = buddy_getstatusmsg(bud);
+ status = buddy_getstatus(bud, NULL);
+ st_msg = buddy_getstatusmsg(bud, NULL);
buffer = g_new(char, 128);
--- a/mcabber/src/hooks.c Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/hooks.c Mon Sep 19 23:32:42 2005 +0200
@@ -60,7 +60,8 @@
// We need to rebuild the list if the sender is unknown or
// if the sender is offline/invisible and hide_offline_buddies is set
if (new_guy ||
- (roster_getstatus(jid) == offline && buddylist_get_hide_offline_buddies()))
+ (roster_getstatus(jid, NULL) == offline &&
+ buddylist_get_hide_offline_buddies()))
{
buddylist_build();
update_roster = TRUE;
@@ -75,13 +76,16 @@
hk_ext_cmd(jid, 'M', 'S', NULL);
}
-inline void hk_statuschange(const char *jid, time_t timestamp,
- enum imstatus status, const char *status_msg)
+inline void hk_statuschange(const char *jid, const char *resname, gchar prio,
+ time_t timestamp, enum imstatus status,
+ const char *status_msg)
{
- scr_LogPrint(LPRINT_LOGNORM, "Buddy status has changed: [%c>%c] <%s> %s",
- imstatus2char[roster_getstatus(jid)], imstatus2char[status], jid,
- ((status_msg) ? status_msg : ""));
- roster_setstatus(jid, status, status_msg);
+ const char *rn = (resname ? resname : "default");
+ scr_LogPrint(LPRINT_LOGNORM, "Buddy status has changed: [%c>%c] <%s/%s> %s",
+ imstatus2char[roster_getstatus(jid, resname)],
+ imstatus2char[status], jid, rn,
+ ((status_msg) ? status_msg : ""));
+ roster_setstatus(jid, rn, prio, status, status_msg);
buddylist_build();
scr_DrawRoster();
hlog_write_status(jid, 0, status, status_msg);
--- a/mcabber/src/hooks.h Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/hooks.h Mon Sep 19 23:32:42 2005 +0200
@@ -8,10 +8,12 @@
inline void hk_message_in(const char *jid, time_t timestamp, const char *msg,
const char *type);
inline void hk_message_out(const char *jid, time_t timestamp, const char *msg);
-inline void hk_statuschange(const char *jid, time_t timestamp,
- enum imstatus status, char const *status_msg);
+inline void hk_statuschange(const char *jid, const char *resname, gchar prio,
+ time_t timestamp, enum imstatus status,
+ char const *status_msg);
inline void hk_mystatuschange(time_t timestamp,
- enum imstatus old_status, enum imstatus new_status, const char *msg);
+ enum imstatus old_status,
+ enum imstatus new_status, const char *msg);
void hk_ext_cmd_init(const char *command);
void hk_ext_cmd(const char *jid, guchar type, guchar info, const char *data);
--- a/mcabber/src/jabglue.c Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/jabglue.c Mon Sep 19 23:32:42 2005 +0200
@@ -99,8 +99,7 @@
char *ptr;
char *alias;
- while ((alias = g_strdup(jid)) == NULL)
- safe_usleep(100);
+ alias = g_strdup(jid);
if ((ptr = strchr(alias, '/')) != NULL) {
*ptr = 0;
@@ -710,12 +709,13 @@
void packethandler(jconn conn, jpacket packet)
{
char *p, *r;
- const char *m;
+ const char *m, *rname;
xmlnode x, y;
char *from=NULL, *type=NULL, *body=NULL, *enc=NULL;
char *ns=NULL;
char *id=NULL;
enum imstatus ust;
+ char bpprio;
jb_reset_keepalive(); // reset keepalive delay
jpacket_reset(packet);
@@ -903,18 +903,18 @@
g_free(r);
break;
}
- x = xmlnode_get_tag(packet->x, "show");
- ust = available;
- if (x) {
- p = xmlnode_get_data(x); if (p) ns = p;
+ p = xmlnode_get_tag_data(packet->x, "priority");
+ if (p && *p) bpprio = (gchar)atoi(p);
+ else bpprio = 0;
- if (ns) {
- if (!strcmp(ns, "away")) ust = away;
- else if (!strcmp(ns, "dnd")) ust = dontdisturb;
- else if (!strcmp(ns, "xa")) ust = notavail;
- else if (!strcmp(ns, "chat")) ust = freeforchat;
- }
+ ust = available;
+ p = xmlnode_get_tag_data(packet->x, "show");
+ if (p) {
+ if (!strcmp(p, "away")) ust = away;
+ else if (!strcmp(p, "dnd")) ust = dontdisturb;
+ else if (!strcmp(p, "xa")) ust = notavail;
+ else if (!strcmp(p, "chat")) ust = freeforchat;
}
if (type && !strcmp(type, "unavailable"))
@@ -927,9 +927,11 @@
// Call hk_statuschange() if status has changed or if the
// status message is different
- m = roster_getstatusmsg(r);
- if ((ust != roster_getstatus(r)) || (p && (!m || strcmp(p, m))))
- hk_statuschange(r, 0, ust, p);
+ rname = strchr(from, '/');
+ if (rname) rname++;
+ m = roster_getstatusmsg(r, rname);
+ if ((ust != roster_getstatus(r, rname)) || (p && (!m || strcmp(p, m))))
+ hk_statuschange(r, rname, bpprio, 0, ust, p);
g_free(r);
if (p) g_free(p);
break;
--- a/mcabber/src/roster.c Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/roster.c Mon Sep 19 23:32:42 2005 +0200
@@ -25,14 +25,26 @@
#include "roster.h"
+/* Resource structure */
+
+typedef struct {
+ gchar *name;
+ gchar prio;
+ enum imstatus status;
+ gchar *status_msg;
+ enum imrole role;
+ gchar *realjid; /* for chatrooms, if buddy's real jid is known */
+} res;
+
/* This is a private structure type for the roster */
typedef struct {
- const gchar *name;
- const gchar *jid;
- const gchar *status_msg;
+ gchar *name;
+ gchar *jid;
guint type;
- enum imstatus status;
+ enum subscr subscription;
+ GSList *resource;
+ res *cur_res;
guint flags;
// list: user -> points to his group; group -> points to its users list
GSList *list;
@@ -49,6 +61,115 @@
GList *alternate_buddy;
+/* ### Resources functions ### */
+
+static void free_all_resources(GSList **reslist)
+{
+ GSList *lip;
+ res *p_res;
+
+ for ( lip = *reslist; lip ; lip = g_slist_next(lip)) {
+ p_res = (res*)lip->data;
+ if (p_res->status_msg) {
+ g_free((gchar*)p_res->status_msg);
+ }
+ if (p_res->name) {
+ g_free((gchar*)p_res->name);
+ }
+ if (p_res->realjid) {
+ g_free((gchar*)p_res->realjid);
+ }
+ }
+ // Free all nodes but the first (which is static)
+ g_slist_free(*reslist);
+ *reslist = NULL;
+}
+
+// Resources are sorted in ascending order
+static gint resource_compare_prio(res *a, res *b) {
+ //return (a->prio - b->prio);
+ if (a->prio < b->prio) return -1;
+ else return 1;
+}
+
+// get_resource(rost, resname)
+// Return a pointer to the resource with name resname, in rost's resources list
+// - if rost has no resources, return NULL
+// - if resname is defined, return the match or NULL
+// - if resname is NULL, the last resource is returned, currently
+// This could change in the future, because we should return the best one
+// (priority? last used? and fall back to the first resource)
+//
+static res *get_resource(roster *rost, const char *resname)
+{
+ GSList *p;
+ res *r = NULL;
+
+ for (p = rost->resource; p; p = g_slist_next(p)) {
+ r = p->data;
+ if (resname && !strcmp(r->name, resname))
+ return r;
+ }
+
+ // The last resource is one of the resources with the highest priority,
+ // however, we don't know if it is the more-recently-used.
+ if (!resname) return r;
+ return NULL;
+}
+
+// get_or_add_resource(rost, resname, priority)
+// - if there is a "resname" resource in rost's resources, return a pointer
+// on this resource
+// - if not, add the resource, set the name, and return a pointer on this
+// new resource
+static res *get_or_add_resource(roster *rost, const char *resname, gchar prio)
+{
+ GSList *p;
+ res *nres;
+
+ if (!resname) return NULL;
+
+ for (p = rost->resource; p; p = g_slist_next(p)) {
+ res *r = p->data;
+ if (!strcmp(r->name, resname))
+ return r;
+ }
+
+ // Resource not found
+ nres = g_new0(res, 1);
+ nres->name = g_strdup(resname);
+ nres->prio = prio;
+ rost->resource = g_slist_insert_sorted(rost->resource, nres,
+ (GCompareFunc)&resource_compare_prio);
+ return nres;
+}
+
+static void del_resource(roster *rost, const char *resname)
+{
+ GSList *p;
+ GSList *p_res_elt = NULL;
+ res *p_res;
+
+ if (!resname) return;
+
+ for (p = rost->resource; p; p = g_slist_next(p)) {
+ res *r = p->data;
+ if (!strcmp(r->name, resname))
+ p_res_elt = p;
+ }
+
+ if (!p_res_elt) return; // Resource not found
+
+ p_res = p_res_elt->data;
+ // Free allocations and delete resource node
+ if (p_res->name) g_free(p_res->name);
+ if (p_res->status_msg) g_free(p_res->status_msg);
+ if (p_res->realjid) g_free(p_res->realjid);
+ rost->resource = g_slist_delete_link(rost->resource, p_res_elt);
+ return;
+}
+
+
/* ### Roster functions ### */
// Comparison function used to search in the roster (compares jids and types)
@@ -80,10 +201,10 @@
sample.type = roster_type;
if (type == jidsearch) {
- sample.jid = jidname;
+ sample.jid = (gchar*)jidname;
comp = (GCompareFunc)&roster_compare_jid_type;
} else if (type == namesearch) {
- sample.name = jidname;
+ sample.name = (gchar*)jidname;
comp = (GCompareFunc)&roster_compare_name;
} else
return NULL; // should not happen
@@ -183,7 +304,7 @@
// Let's free memory (jid, name, status message)
if (roster_usr->jid) g_free((gchar*)roster_usr->jid);
if (roster_usr->name) g_free((gchar*)roster_usr->name);
- if (roster_usr->status_msg) g_free((gchar*)roster_usr->status_msg);
+ free_all_resources(&roster_usr->resource);
g_free(roster_usr);
// That's a little complex, we need to dereference twice
@@ -220,7 +341,7 @@
// Free name and jid
if (roster_usr->jid) g_free((gchar*)roster_usr->jid);
if (roster_usr->name) g_free((gchar*)roster_usr->name);
- if (roster_usr->status_msg) g_free((gchar*)roster_usr->status_msg);
+ free_all_resources(&roster_usr->resource);
g_free(roster_usr);
sl_usr = g_slist_next(sl_usr);
}
@@ -243,25 +364,38 @@
}
}
-void roster_setstatus(const char *jid, enum imstatus bstat,
- const char *status_msg)
+void roster_setstatus(const char *jid, const char *resname, gchar prio,
+ enum imstatus bstat, const char *status_msg)
{
GSList *sl_user;
roster *roster_usr;
+ res *p_res;
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);
+ // If there is no resource name, we can leave now
+ if (!resname) return;
+
roster_usr = (roster*)sl_user->data;
- roster_usr->status = bstat;
- if (roster_usr->status_msg) {
- g_free((gchar*)roster_usr->status_msg);
- roster_usr->status_msg = NULL;
+
+ // If bstat is offline, we MUST delete the resource, actually
+ if (bstat == offline) {
+ del_resource(roster_usr, resname);
+ return;
+ }
+
+ // New or updated resource
+ p_res = get_or_add_resource(roster_usr, resname, prio);
+ p_res->status = bstat;
+ if (p_res->status_msg) {
+ g_free((gchar*)p_res->status_msg);
+ p_res->status_msg = NULL;
}
if (status_msg)
- roster_usr->status_msg = g_strdup(status_msg);
+ p_res->status_msg = g_strdup(status_msg);
}
// roster_setflags()
@@ -347,30 +481,38 @@
roster_usr->type = type;
}
-enum imstatus roster_getstatus(const char *jid)
+enum imstatus roster_getstatus(const char *jid, const char *resname)
{
GSList *sl_user;
roster *roster_usr;
+ res *p_res;
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;
+ p_res = get_resource(roster_usr, resname);
+ if (p_res)
+ return p_res->status;
+ return offline;
}
-const char *roster_getstatusmsg(const char *jid)
+const char *roster_getstatusmsg(const char *jid, const char *resname)
{
GSList *sl_user;
roster *roster_usr;
+ res *p_res;
sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
if (sl_user == NULL)
return NULL; // Not in the roster, anyway...
roster_usr = (roster*)sl_user->data;
- return roster_usr->status_msg;
+ p_res = get_resource(roster_usr, resname);
+ if (p_res)
+ return p_res->status_msg;
+ return NULL;
}
guint roster_gettype(const char *jid)
@@ -466,7 +608,7 @@
// - group isn't hidden (shrunk)
// - this is the current_buddy
if (!hide_offline_buddies || roster_usrelt == roster_current_buddy ||
- (buddy_getstatus((gpointer)roster_usrelt) != offline) ||
+ (buddy_getstatus((gpointer)roster_usrelt, NULL) != 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?
@@ -544,13 +686,14 @@
sl_clone = roster_add_user(roster_usr->jid, roster_usr->name,
newgroupname, roster_usr->type);
roster_clone = (roster*)sl_clone->data;
- roster_clone->status = roster_usr->status;
- roster_clone->flags = roster_usr->flags;
+ roster_clone->flags = roster_usr->flags;
+ roster_clone->resource = roster_usr->resource;
+ roster_usr->resource = NULL;
// Free old buddy
if (roster_usr->jid) g_free((gchar*)roster_usr->jid);
if (roster_usr->name) g_free((gchar*)roster_usr->name);
- if (roster_usr->status_msg) g_free((gchar*)roster_usr->status_msg);
+ free_all_resources(&roster_usr->resource);
g_free(roster_usr);
// If new new group is folded, the curren_buddy will be lost, and the
@@ -629,16 +772,22 @@
return roster_usr->type;
}
-enum imstatus buddy_getstatus(gpointer rosterdata)
+enum imstatus buddy_getstatus(gpointer rosterdata, const char *resname)
{
roster *roster_usr = rosterdata;
- return roster_usr->status;
+ res *p_res = get_resource(roster_usr, resname);
+ if (p_res)
+ return p_res->status;
+ return offline;
}
-const char *buddy_getstatusmsg(gpointer rosterdata)
+const char *buddy_getstatusmsg(gpointer rosterdata, const char *resname)
{
roster *roster_usr = rosterdata;
- return roster_usr->status_msg;
+ res *p_res = get_resource(roster_usr, resname);
+ if (p_res)
+ return p_res->status_msg;
+ return NULL;
}
// buddy_setflags()
--- a/mcabber/src/roster.h Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/roster.h Mon Sep 19 23:32:42 2005 +0200
@@ -5,6 +5,20 @@
# include "jabglue.h"
+enum imrole {
+ role_none,
+ role_moderator,
+ role_participant,
+ role_visitor
+};
+
+enum subscr {
+ sub_none,
+ sub_to,
+ sub_from,
+ sub_both
+};
+
enum findwhat {
jidsearch,
namesearch
@@ -36,16 +50,16 @@
guint type);
void roster_del_user(const char *jid);
void roster_free(void);
-void roster_setstatus(const char *jid, enum imstatus bstat,
- const char *status_msg);
+void roster_setstatus(const char *jid, const char *resname, gchar prio,
+ enum imstatus bstat, const char *status_msg);
void roster_setflags(const char *jid, guint flags, guint value);
void roster_msg_setflag(const char *jid, guint value);
void roster_settype(const char *jid, guint type);
-enum imstatus roster_getstatus(const char *jid);
-const char *roster_getstatusmsg(const char *jid);
+enum imstatus roster_getstatus(const char *jid, const char *resname);
+const char *roster_getstatusmsg(const char *jid, const char *resname);
guint roster_gettype(const char *jid);
inline guint roster_exists(const char *jidname, enum findwhat type,
- guint roster_type);
+ guint roster_type);
void buddylist_build(void);
void buddy_hide_group(gpointer rosterdata, int hide);
@@ -58,8 +72,8 @@
void buddy_setgroup(gpointer rosterdata, char *newgroupname);
const char *buddy_getgroupname(gpointer rosterdata);
gpointer buddy_getgroup(gpointer rosterdata);
-enum imstatus buddy_getstatus(gpointer rosterdata);
-const char *buddy_getstatusmsg(gpointer rosterdata);
+enum imstatus buddy_getstatus(gpointer rosterdata, const char *resname);
+const char *buddy_getstatusmsg(gpointer rosterdata, const char *resname);
void buddy_setflags(gpointer rosterdata, guint flags, guint value);
guint buddy_getflags(gpointer rosterdata);
GList *buddy_search(char *string);
--- a/mcabber/src/screen.c Fri Sep 16 21:49:39 2005 +0200
+++ b/mcabber/src/screen.c Mon Sep 19 23:32:42 2005 +0200
@@ -733,7 +733,7 @@
pending = '#';
}
- budstate = buddy_getstatus(BUDDATA(buddy));
+ budstate = buddy_getstatus(BUDDATA(buddy), NULL);
if (budstate >= 0 && budstate < imstatus_size && currentstatus != offline)
status = imstatus2char[budstate];
if (buddy == current_buddy) {
@@ -849,7 +849,7 @@
if (!current_buddy || !newbuddy) return;
if (newbuddy == current_buddy) return;
- prev_st = buddy_getstatus(BUDDATA(current_buddy));
+ prev_st = buddy_getstatus(BUDDATA(current_buddy), NULL);
buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE);
if (chatmode)
alternate_buddy = current_buddy;