47 GList *buddylist; |
59 GList *buddylist; |
48 GList *current_buddy; |
60 GList *current_buddy; |
49 GList *alternate_buddy; |
61 GList *alternate_buddy; |
50 |
62 |
51 |
63 |
|
64 /* ### Resources functions ### */ |
|
65 |
|
66 static void free_all_resources(GSList **reslist) |
|
67 { |
|
68 GSList *lip; |
|
69 res *p_res; |
|
70 |
|
71 for ( lip = *reslist; lip ; lip = g_slist_next(lip)) { |
|
72 p_res = (res*)lip->data; |
|
73 if (p_res->status_msg) { |
|
74 g_free((gchar*)p_res->status_msg); |
|
75 } |
|
76 if (p_res->name) { |
|
77 g_free((gchar*)p_res->name); |
|
78 } |
|
79 if (p_res->realjid) { |
|
80 g_free((gchar*)p_res->realjid); |
|
81 } |
|
82 } |
|
83 // Free all nodes but the first (which is static) |
|
84 g_slist_free(*reslist); |
|
85 *reslist = NULL; |
|
86 } |
|
87 |
|
88 // Resources are sorted in ascending order |
|
89 static gint resource_compare_prio(res *a, res *b) { |
|
90 //return (a->prio - b->prio); |
|
91 if (a->prio < b->prio) return -1; |
|
92 else return 1; |
|
93 } |
|
94 |
|
95 // get_resource(rost, resname) |
|
96 // Return a pointer to the resource with name resname, in rost's resources list |
|
97 // - if rost has no resources, return NULL |
|
98 // - if resname is defined, return the match or NULL |
|
99 // - if resname is NULL, the last resource is returned, currently |
|
100 // This could change in the future, because we should return the best one |
|
101 // (priority? last used? and fall back to the first resource) |
|
102 // |
|
103 static res *get_resource(roster *rost, const char *resname) |
|
104 { |
|
105 GSList *p; |
|
106 res *r = NULL; |
|
107 |
|
108 for (p = rost->resource; p; p = g_slist_next(p)) { |
|
109 r = p->data; |
|
110 if (resname && !strcmp(r->name, resname)) |
|
111 return r; |
|
112 } |
|
113 |
|
114 // The last resource is one of the resources with the highest priority, |
|
115 // however, we don't know if it is the more-recently-used. |
|
116 if (!resname) return r; |
|
117 return NULL; |
|
118 } |
|
119 |
|
120 // get_or_add_resource(rost, resname, priority) |
|
121 // - if there is a "resname" resource in rost's resources, return a pointer |
|
122 // on this resource |
|
123 // - if not, add the resource, set the name, and return a pointer on this |
|
124 // new resource |
|
125 static res *get_or_add_resource(roster *rost, const char *resname, gchar prio) |
|
126 { |
|
127 GSList *p; |
|
128 res *nres; |
|
129 |
|
130 if (!resname) return NULL; |
|
131 |
|
132 for (p = rost->resource; p; p = g_slist_next(p)) { |
|
133 res *r = p->data; |
|
134 if (!strcmp(r->name, resname)) |
|
135 return r; |
|
136 } |
|
137 |
|
138 // Resource not found |
|
139 nres = g_new0(res, 1); |
|
140 nres->name = g_strdup(resname); |
|
141 nres->prio = prio; |
|
142 rost->resource = g_slist_insert_sorted(rost->resource, nres, |
|
143 (GCompareFunc)&resource_compare_prio); |
|
144 return nres; |
|
145 } |
|
146 |
|
147 static void del_resource(roster *rost, const char *resname) |
|
148 { |
|
149 GSList *p; |
|
150 GSList *p_res_elt = NULL; |
|
151 res *p_res; |
|
152 |
|
153 if (!resname) return; |
|
154 |
|
155 for (p = rost->resource; p; p = g_slist_next(p)) { |
|
156 res *r = p->data; |
|
157 if (!strcmp(r->name, resname)) |
|
158 p_res_elt = p; |
|
159 } |
|
160 |
|
161 if (!p_res_elt) return; // Resource not found |
|
162 |
|
163 p_res = p_res_elt->data; |
|
164 // Free allocations and delete resource node |
|
165 if (p_res->name) g_free(p_res->name); |
|
166 if (p_res->status_msg) g_free(p_res->status_msg); |
|
167 if (p_res->realjid) g_free(p_res->realjid); |
|
168 rost->resource = g_slist_delete_link(rost->resource, p_res_elt); |
|
169 return; |
|
170 } |
|
171 |
|
172 |
52 /* ### Roster functions ### */ |
173 /* ### Roster functions ### */ |
53 |
174 |
54 // Comparison function used to search in the roster (compares jids and types) |
175 // Comparison function used to search in the roster (compares jids and types) |
55 static gint roster_compare_jid_type(roster *a, roster *b) { |
176 static gint roster_compare_jid_type(roster *a, roster *b) { |
56 if (! (a->type & b->type)) |
177 if (! (a->type & b->type)) |
78 if (!roster_type) |
199 if (!roster_type) |
79 roster_type = ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP; |
200 roster_type = ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP; |
80 |
201 |
81 sample.type = roster_type; |
202 sample.type = roster_type; |
82 if (type == jidsearch) { |
203 if (type == jidsearch) { |
83 sample.jid = jidname; |
204 sample.jid = (gchar*)jidname; |
84 comp = (GCompareFunc)&roster_compare_jid_type; |
205 comp = (GCompareFunc)&roster_compare_jid_type; |
85 } else if (type == namesearch) { |
206 } else if (type == namesearch) { |
86 sample.name = jidname; |
207 sample.name = (gchar*)jidname; |
87 comp = (GCompareFunc)&roster_compare_name; |
208 comp = (GCompareFunc)&roster_compare_name; |
88 } else |
209 } else |
89 return NULL; // should not happen |
210 return NULL; // should not happen |
90 |
211 |
91 while (sl_roster_elt) { |
212 while (sl_roster_elt) { |
181 if (node) unread_list = g_slist_delete_link(unread_list, node); |
302 if (node) unread_list = g_slist_delete_link(unread_list, node); |
182 |
303 |
183 // Let's free memory (jid, name, status message) |
304 // Let's free memory (jid, name, status message) |
184 if (roster_usr->jid) g_free((gchar*)roster_usr->jid); |
305 if (roster_usr->jid) g_free((gchar*)roster_usr->jid); |
185 if (roster_usr->name) g_free((gchar*)roster_usr->name); |
306 if (roster_usr->name) g_free((gchar*)roster_usr->name); |
186 if (roster_usr->status_msg) g_free((gchar*)roster_usr->status_msg); |
307 free_all_resources(&roster_usr->resource); |
187 g_free(roster_usr); |
308 g_free(roster_usr); |
188 |
309 |
189 // That's a little complex, we need to dereference twice |
310 // That's a little complex, we need to dereference twice |
190 sl_group = ((roster*)sl_user->data)->list; |
311 sl_group = ((roster*)sl_user->data)->list; |
191 sl_group_listptr = &((roster*)(sl_group->data))->list; |
312 sl_group_listptr = &((roster*)(sl_group->data))->list; |
241 if (buddylist) |
362 if (buddylist) |
242 buddylist_build(); |
363 buddylist_build(); |
243 } |
364 } |
244 } |
365 } |
245 |
366 |
246 void roster_setstatus(const char *jid, enum imstatus bstat, |
367 void roster_setstatus(const char *jid, const char *resname, gchar prio, |
247 const char *status_msg) |
368 enum imstatus bstat, const char *status_msg) |
248 { |
369 { |
249 GSList *sl_user; |
370 GSList *sl_user; |
250 roster *roster_usr; |
371 roster *roster_usr; |
|
372 res *p_res; |
251 |
373 |
252 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
374 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
253 // If we can't find it, we add it |
375 // If we can't find it, we add it |
254 if (sl_user == NULL) |
376 if (sl_user == NULL) |
255 sl_user = roster_add_user(jid, NULL, NULL, ROSTER_TYPE_USER); |
377 sl_user = roster_add_user(jid, NULL, NULL, ROSTER_TYPE_USER); |
256 |
378 |
|
379 // If there is no resource name, we can leave now |
|
380 if (!resname) return; |
|
381 |
257 roster_usr = (roster*)sl_user->data; |
382 roster_usr = (roster*)sl_user->data; |
258 roster_usr->status = bstat; |
383 |
259 if (roster_usr->status_msg) { |
384 // If bstat is offline, we MUST delete the resource, actually |
260 g_free((gchar*)roster_usr->status_msg); |
385 if (bstat == offline) { |
261 roster_usr->status_msg = NULL; |
386 del_resource(roster_usr, resname); |
|
387 return; |
|
388 } |
|
389 |
|
390 // New or updated resource |
|
391 p_res = get_or_add_resource(roster_usr, resname, prio); |
|
392 p_res->status = bstat; |
|
393 if (p_res->status_msg) { |
|
394 g_free((gchar*)p_res->status_msg); |
|
395 p_res->status_msg = NULL; |
262 } |
396 } |
263 if (status_msg) |
397 if (status_msg) |
264 roster_usr->status_msg = g_strdup(status_msg); |
398 p_res->status_msg = g_strdup(status_msg); |
265 } |
399 } |
266 |
400 |
267 // roster_setflags() |
401 // roster_setflags() |
268 // Set one or several flags to value (TRUE/FALSE) |
402 // Set one or several flags to value (TRUE/FALSE) |
269 void roster_setflags(const char *jid, guint flags, guint value) |
403 void roster_setflags(const char *jid, guint flags, guint value) |
345 |
479 |
346 roster_usr = (roster*)sl_user->data; |
480 roster_usr = (roster*)sl_user->data; |
347 roster_usr->type = type; |
481 roster_usr->type = type; |
348 } |
482 } |
349 |
483 |
350 enum imstatus roster_getstatus(const char *jid) |
484 enum imstatus roster_getstatus(const char *jid, const char *resname) |
351 { |
485 { |
352 GSList *sl_user; |
486 GSList *sl_user; |
353 roster *roster_usr; |
487 roster *roster_usr; |
|
488 res *p_res; |
354 |
489 |
355 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
490 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
356 if (sl_user == NULL) |
491 if (sl_user == NULL) |
357 return offline; // Not in the roster, anyway... |
492 return offline; // Not in the roster, anyway... |
358 |
493 |
359 roster_usr = (roster*)sl_user->data; |
494 roster_usr = (roster*)sl_user->data; |
360 return roster_usr->status; |
495 p_res = get_resource(roster_usr, resname); |
361 } |
496 if (p_res) |
362 |
497 return p_res->status; |
363 const char *roster_getstatusmsg(const char *jid) |
498 return offline; |
|
499 } |
|
500 |
|
501 const char *roster_getstatusmsg(const char *jid, const char *resname) |
364 { |
502 { |
365 GSList *sl_user; |
503 GSList *sl_user; |
366 roster *roster_usr; |
504 roster *roster_usr; |
|
505 res *p_res; |
367 |
506 |
368 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
507 sl_user = roster_find(jid, jidsearch, ROSTER_TYPE_USER|ROSTER_TYPE_AGENT); |
369 if (sl_user == NULL) |
508 if (sl_user == NULL) |
370 return NULL; // Not in the roster, anyway... |
509 return NULL; // Not in the roster, anyway... |
371 |
510 |
372 roster_usr = (roster*)sl_user->data; |
511 roster_usr = (roster*)sl_user->data; |
373 return roster_usr->status_msg; |
512 p_res = get_resource(roster_usr, resname); |
|
513 if (p_res) |
|
514 return p_res->status_msg; |
|
515 return NULL; |
374 } |
516 } |
375 |
517 |
376 guint roster_gettype(const char *jid) |
518 guint roster_gettype(const char *jid) |
377 { |
519 { |
378 GSList *sl_user; |
520 GSList *sl_user; |
464 // - buddy has a lock (for example the buddy window is currently open) |
606 // - buddy has a lock (for example the buddy window is currently open) |
465 // - buddy has a pending (non-read) message |
607 // - buddy has a pending (non-read) message |
466 // - group isn't hidden (shrunk) |
608 // - group isn't hidden (shrunk) |
467 // - this is the current_buddy |
609 // - this is the current_buddy |
468 if (!hide_offline_buddies || roster_usrelt == roster_current_buddy || |
610 if (!hide_offline_buddies || roster_usrelt == roster_current_buddy || |
469 (buddy_getstatus((gpointer)roster_usrelt) != offline) || |
611 (buddy_getstatus((gpointer)roster_usrelt, NULL) != offline) || |
470 (buddy_getflags((gpointer)roster_usrelt) & |
612 (buddy_getflags((gpointer)roster_usrelt) & |
471 (ROSTER_FLAG_LOCK | ROSTER_FLAG_MSG))) { |
613 (ROSTER_FLAG_LOCK | ROSTER_FLAG_MSG))) { |
472 // This user should be added. Maybe the group hasn't been added yet? |
614 // This user should be added. Maybe the group hasn't been added yet? |
473 if (pending_group && |
615 if (pending_group && |
474 (hide_offline_buddies || roster_usrelt == roster_current_buddy)) { |
616 (hide_offline_buddies || roster_usrelt == roster_current_buddy)) { |
542 |
684 |
543 // Add the buddy to its new group; actually we "clone" this buddy... |
685 // Add the buddy to its new group; actually we "clone" this buddy... |
544 sl_clone = roster_add_user(roster_usr->jid, roster_usr->name, |
686 sl_clone = roster_add_user(roster_usr->jid, roster_usr->name, |
545 newgroupname, roster_usr->type); |
687 newgroupname, roster_usr->type); |
546 roster_clone = (roster*)sl_clone->data; |
688 roster_clone = (roster*)sl_clone->data; |
547 roster_clone->status = roster_usr->status; |
689 roster_clone->flags = roster_usr->flags; |
548 roster_clone->flags = roster_usr->flags; |
690 roster_clone->resource = roster_usr->resource; |
|
691 roster_usr->resource = NULL; |
549 |
692 |
550 // Free old buddy |
693 // Free old buddy |
551 if (roster_usr->jid) g_free((gchar*)roster_usr->jid); |
694 if (roster_usr->jid) g_free((gchar*)roster_usr->jid); |
552 if (roster_usr->name) g_free((gchar*)roster_usr->name); |
695 if (roster_usr->name) g_free((gchar*)roster_usr->name); |
553 if (roster_usr->status_msg) g_free((gchar*)roster_usr->status_msg); |
696 free_all_resources(&roster_usr->resource); |
554 g_free(roster_usr); |
697 g_free(roster_usr); |
555 |
698 |
556 // If new new group is folded, the curren_buddy will be lost, and the |
699 // If new new group is folded, the curren_buddy will be lost, and the |
557 // chat window won't be correctly refreshed. So we make sure it isn't... |
700 // chat window won't be correctly refreshed. So we make sure it isn't... |
558 ((roster*)((GSList*)roster_clone->list)->data)->flags &= ~ROSTER_FLAG_HIDE; |
701 ((roster*)((GSList*)roster_clone->list)->data)->flags &= ~ROSTER_FLAG_HIDE; |
627 { |
770 { |
628 roster *roster_usr = rosterdata; |
771 roster *roster_usr = rosterdata; |
629 return roster_usr->type; |
772 return roster_usr->type; |
630 } |
773 } |
631 |
774 |
632 enum imstatus buddy_getstatus(gpointer rosterdata) |
775 enum imstatus buddy_getstatus(gpointer rosterdata, const char *resname) |
633 { |
776 { |
634 roster *roster_usr = rosterdata; |
777 roster *roster_usr = rosterdata; |
635 return roster_usr->status; |
778 res *p_res = get_resource(roster_usr, resname); |
636 } |
779 if (p_res) |
637 |
780 return p_res->status; |
638 const char *buddy_getstatusmsg(gpointer rosterdata) |
781 return offline; |
639 { |
782 } |
640 roster *roster_usr = rosterdata; |
783 |
641 return roster_usr->status_msg; |
784 const char *buddy_getstatusmsg(gpointer rosterdata, const char *resname) |
|
785 { |
|
786 roster *roster_usr = rosterdata; |
|
787 res *p_res = get_resource(roster_usr, resname); |
|
788 if (p_res) |
|
789 return p_res->status_msg; |
|
790 return NULL; |
642 } |
791 } |
643 |
792 |
644 // buddy_setflags() |
793 // buddy_setflags() |
645 // Set one or several flags to value (TRUE/FALSE) |
794 // Set one or several flags to value (TRUE/FALSE) |
646 void buddy_setflags(gpointer rosterdata, guint flags, guint value) |
795 void buddy_setflags(gpointer rosterdata, guint flags, guint value) |