src/status.c

changeset 9949
377cd65fab3d
parent 9944
71ef020ec4b0
child 10006
800a81666868
equal deleted inserted replaced
9948:2642975ffb85 9949:377cd65fab3d
20 * 20 *
21 * You should have received a copy of the GNU General Public License 21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software 22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */ 24 */
25 25 #include "internal.h"
26
27 #include "blist.h"
28 #include "debug.h"
29 #include "prefs.h"
26 #include "status.h" 30 #include "status.h"
27 #include "internal.h"
28 #include "debug.h"
29 #include "util.h" 31 #include "util.h"
30 32
31 /* XXX CORE/UI */ 33 /**
32 #include "away.h" 34 * A type of status.
33 #include "gtkgaim.h" 35 */
34 36 struct _GaimStatusType
35 37 {
36 /* for people like myself who are too lazy to add an away msg :) */ 38 GaimStatusPrimitive primitive;
37 /* I don't know who "myself" is in this context. The exclamation point 39
38 * makes it slightly less boring ;) */ 40 char *id;
39 #define BORING_DEFAULT_AWAY_MSG _("Sorry, I ran out for a bit!") 41 char *name;
40 42 char *primary_attr_id;
41 /* XML File Saving */ 43
42 44 gboolean saveable;
43 /* All of this code is adapted from Nathan Walp's. It's adapted all over the place 45 gboolean user_settable;
44 * for accounts, the buddy list, pounces, preferences, and the likes. It would be 46 gboolean independent;
45 * neat if we could somehow make this more generic. */ 47
46 static gboolean status_loaded = FALSE; 48 GList *attrs;
47 static guint status_save_timer = 0; 49 };
48 50
49 51 /**
50 typedef enum 52 * A status attribute.
51 { 53 */
52 TAG_NONE = 0, 54 struct _GaimStatusAttr
53 TAG_STATUS, 55 {
54 TAG_STATE, 56 char *id;
55 TAG_MESSAGE, 57 char *name;
56 58 GaimValue *value_type;
57 } StatusParserTag; 59 };
58 60
61 /**
62 * A list of statuses.
63 */
64 struct _GaimPresence
65 {
66 GaimPresenceContext context;
67
68 gboolean idle;
69 time_t idle_time;
70
71 unsigned int warning_level;
72
73 GList *statuses;
74 GHashTable *status_table;
75
76 GaimStatus *active_status;
77
78 union
79 {
80 GaimAccount *account;
81
82 struct
83 {
84 GaimConversation *conv;
85 char *user;
86
87 } chat;
88
89 struct
90 {
91 GaimAccount *account;
92 char *name;
93 size_t ref_count;
94 GList *buddies;
95
96 } buddy;
97
98 } u;
99 };
100
101 /**
102 * An active status.
103 */
104 struct _GaimStatus
105 {
106 GaimStatusType *type;
107 GaimPresence *presence;
108
109 const char *title;
110
111 gboolean active;
112
113 GHashTable *attr_values;
114 };
59 115
60 typedef struct 116 typedef struct
61 { 117 {
62 StatusParserTag tag; 118 GaimAccount *account;
63 GString *buffer; 119 char *name;
64 struct away_message *am; 120
65 121 } GaimStatusBuddyKey;
66 } StatusParserData; 122
123
124 #if 0
125 static GList *stored_statuses = NULL;
126
127 /*
128 * XXX This stuff should be removed in a few versions. It stores the
129 * old v1 status stuff so we can write it later. We don't write out
130 * the new status stuff, though. These should all die soon, as the
131 * old status.xml was created before the new status system's design
132 * was created.
133 *
134 * -- ChipX86
135 */
136 typedef struct
137 {
138 char *name;
139 char *state;
140 char *message;
141
142 } GaimStatusV1Info;
143
144 static GList *v1_statuses = NULL;
145 #endif
146
147
148 static int primitive_scores[] =
149 {
150 0, /* unset */
151 -500, /* offline */
152 0, /* online */
153 100, /* available */
154 -75, /* unavailable */
155 -50, /* hidden */
156 -100, /* away */
157 -200 /* extended away */
158 -10, /* idle, special case. */
159 -5 /* idle time, special case. */
160 };
161
162 static GHashTable *buddy_presences = NULL;
163
164 #define SCORE_IDLE 5
165 #define SCORE_IDLE_TIME 6
166
167 /**************************************************************************
168 * GaimStatusType API
169 **************************************************************************/
170 GaimStatusType *
171 gaim_status_type_new_full(GaimStatusPrimitive primitive, const char *id,
172 const char *name, gboolean saveable,
173 gboolean user_settable, gboolean independent)
174 {
175 GaimStatusType *status_type;
176
177 g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL);
178 g_return_val_if_fail(id != NULL, NULL);
179 g_return_val_if_fail(name != NULL, NULL);
180
181 status_type = g_new0(GaimStatusType, 1);
182
183 status_type->primitive = primitive;
184 status_type->id = g_strdup(id);
185 status_type->name = g_strdup(name);
186 status_type->saveable = saveable;
187 status_type->user_settable = user_settable;
188 status_type->independent = independent;
189
190 return status_type;
191 }
192
193 GaimStatusType *
194 gaim_status_type_new(GaimStatusPrimitive primitive, const char *id,
195 const char *name, gboolean user_settable)
196 {
197 g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL);
198 g_return_val_if_fail(id != NULL, NULL);
199 g_return_val_if_fail(name != NULL, NULL);
200
201 return gaim_status_type_new_full(primitive, id, name, FALSE,
202 user_settable, FALSE);
203 }
204
205 GaimStatusType *
206 gaim_status_type_new_with_attrs(GaimStatusPrimitive primitive,
207 const char *id, const char *name,
208 gboolean saveable, gboolean user_settable,
209 gboolean independent, const char *attr_id,
210 const char *attr_name, GaimValue *attr_value,
211 ...)
212 {
213 GaimStatusType *status_type;
214 va_list args;
215
216 g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL);
217 g_return_val_if_fail(id != NULL, NULL);
218 g_return_val_if_fail(name != NULL, NULL);
219 g_return_val_if_fail(attr_name != NULL, NULL);
220 g_return_val_if_fail(attr_value != NULL, NULL);
221
222 status_type = gaim_status_type_new_full(primitive, id, name, saveable,
223 user_settable, independent);
224
225 gaim_status_type_add_attr(status_type, attr_id, attr_name, attr_value);
226
227 va_start(args, attr_value);
228 gaim_status_type_add_attrs_vargs(status_type, args);
229 va_end(args);
230
231 return status_type;
232 }
233
234 void
235 gaim_status_type_destroy(GaimStatusType *status_type)
236 {
237 GList *l;
238
239 g_return_if_fail(status_type != NULL);
240
241 g_free(status_type->id);
242 g_free(status_type->name);
243
244 if (status_type->primary_attr_id != NULL)
245 g_free(status_type->primary_attr_id);
246
247 if (status_type->attrs != NULL)
248 {
249 for (l = status_type->attrs; l != NULL; l = l->next)
250 gaim_status_attr_destroy((GaimStatusAttr *)l->data);
251
252 g_list_free(status_type->attrs);
253 }
254
255 g_free(status_type);
256 }
257
258 void
259 gaim_status_type_set_primary_attr(GaimStatusType *status_type, const char *id)
260 {
261 g_return_if_fail(status_type != NULL);
262
263 if (status_type->primary_attr_id != NULL)
264 g_free(status_type->primary_attr_id);
265
266 status_type->primary_attr_id = (id == NULL ? NULL : g_strdup(id));
267 }
268
269 void
270 gaim_status_type_add_attr(GaimStatusType *status_type, const char *id,\
271 const char *name, GaimValue *value)
272 {
273 GaimStatusAttr *attr;
274
275 g_return_if_fail(status_type != NULL);
276 g_return_if_fail(id != NULL);
277 g_return_if_fail(name != NULL);
278 g_return_if_fail(value != NULL);
279
280 attr = gaim_status_attr_new(id, name, value);
281
282 status_type->attrs = g_list_append(status_type->attrs, attr);
283 }
284
285 void
286 gaim_status_type_add_attrs(GaimStatusType *status_type, const char *id,
287 const char *name, GaimValue *value, ...)
288 {
289 va_list args;
290
291 g_return_if_fail(status_type != NULL);
292 g_return_if_fail(id != NULL);
293 g_return_if_fail(name != NULL);
294 g_return_if_fail(value != NULL);
295
296 /* Add the first. */
297 gaim_status_type_add_attr(status_type, id, name, value);
298
299 va_start(args, value);
300 gaim_status_type_add_attrs_vargs(status_type, args);
301 va_end(args);
302 }
303
304 void
305 gaim_status_type_add_attrs_vargs(GaimStatusType *status_type, va_list args)
306 {
307 const char *id, *name;
308 GaimValue *value;
309
310 g_return_if_fail(status_type != NULL);
311
312 while ((id = va_arg(args, const char *)) != NULL)
313 {
314 name = va_arg(args, const char *);
315 g_return_if_fail(name != NULL);
316
317 value = va_arg(args, GaimValue *);
318 g_return_if_fail(value != NULL);
319
320 gaim_status_type_add_attr(status_type, id, name, value);
321 }
322 }
323
324 GaimStatusPrimitive
325 gaim_status_type_get_primitive(const GaimStatusType *status_type)
326 {
327 g_return_val_if_fail(status_type != NULL, GAIM_STATUS_UNSET);
328
329 return status_type->primitive;
330 }
331
332 const char *
333 gaim_status_type_get_id(const GaimStatusType *status_type)
334 {
335 g_return_val_if_fail(status_type != NULL, NULL);
336
337 return status_type->id;
338 }
339
340 const char *
341 gaim_status_type_get_name(const GaimStatusType *status_type)
342 {
343 g_return_val_if_fail(status_type != NULL, NULL);
344
345 return status_type->name;
346 }
347
348 gboolean
349 gaim_status_type_is_saveable(const GaimStatusType *status_type)
350 {
351 g_return_val_if_fail(status_type != NULL, FALSE);
352
353 return status_type->saveable;
354 }
355
356 gboolean
357 gaim_status_type_is_user_settable(const GaimStatusType *status_type)
358 {
359 g_return_val_if_fail(status_type != NULL, FALSE);
360
361 return status_type->user_settable;
362 }
363
364 gboolean
365 gaim_status_type_is_independent(const GaimStatusType *status_type)
366 {
367 g_return_val_if_fail(status_type != NULL, FALSE);
368
369 return status_type->independent;
370 }
371
372 gboolean
373 gaim_status_type_is_available(const GaimStatusType *status_type)
374 {
375 GaimStatusPrimitive primitive;
376
377 g_return_val_if_fail(status_type != NULL, FALSE);
378
379 primitive = gaim_status_type_get_primitive(status_type);
380
381 return (primitive == GAIM_STATUS_AVAILABLE ||
382 primitive == GAIM_STATUS_HIDDEN);
383 }
384
385 const char *
386 gaim_status_type_get_primary_attr(const GaimStatusType *status_type)
387 {
388 g_return_val_if_fail(status_type != NULL, NULL);
389
390 return status_type->primary_attr_id;
391 }
392
393 GaimStatusAttr *
394 gaim_status_type_get_attr(const GaimStatusType *status_type, const char *id)
395 {
396 GList *l;
397
398 g_return_val_if_fail(status_type != NULL, NULL);
399 g_return_val_if_fail(id != NULL, NULL);
400
401 for (l = status_type->attrs; l != NULL; l = l->next)
402 {
403 GaimStatusAttr *attr = (GaimStatusAttr *)l->data;
404
405 if (!strcmp(gaim_status_attr_get_id(attr), id))
406 return attr;
407 }
408
409 return NULL;
410 }
411
412 const GList *
413 gaim_status_type_get_attrs(const GaimStatusType *status_type)
414 {
415 g_return_val_if_fail(status_type != NULL, NULL);
416
417 return status_type->attrs;
418 }
419
420
421 /**************************************************************************
422 * GaimStatusAttr API
423 **************************************************************************/
424 GaimStatusAttr *
425 gaim_status_attr_new(const char *id, const char *name, GaimValue *value_type)
426 {
427 GaimStatusAttr *attr;
428
429 g_return_val_if_fail(id != NULL, NULL);
430 g_return_val_if_fail(name != NULL, NULL);
431 g_return_val_if_fail(value_type != NULL, NULL);
432
433 attr = g_new0(GaimStatusAttr, 1);
434
435 attr->id = g_strdup(id);
436 attr->name = g_strdup(name);
437 attr->value_type = value_type;
438
439 return attr;
440 }
441
442 void
443 gaim_status_attr_destroy(GaimStatusAttr *attr)
444 {
445 g_return_if_fail(attr != NULL);
446
447 g_free(attr->id);
448 g_free(attr->name);
449
450 gaim_value_destroy(attr->value_type);
451
452 g_free(attr);
453 }
454
455 const char *
456 gaim_status_attr_get_id(const GaimStatusAttr *attr)
457 {
458 g_return_val_if_fail(attr != NULL, NULL);
459
460 return attr->id;
461 }
462
463 const char *
464 gaim_status_attr_get_name(const GaimStatusAttr *attr)
465 {
466 g_return_val_if_fail(attr != NULL, NULL);
467
468 return attr->name;
469 }
470
471 GaimValue *
472 gaim_status_attr_get_value_type(const GaimStatusAttr *attr)
473 {
474 g_return_val_if_fail(attr != NULL, NULL);
475
476 return attr->value_type;
477 }
478
479
480 /**************************************************************************
481 * GaimStatus API
482 **************************************************************************/
483 GaimStatus *
484 gaim_status_new(GaimStatusType *status_type, GaimPresence *presence)
485 {
486 GaimStatus *status;
487 const GList *l;
488
489 g_return_val_if_fail(status_type != NULL, NULL);
490 g_return_val_if_fail(presence != NULL, NULL);
491
492 status = g_new0(GaimStatus, 1);
493
494 status->type = status_type;
495 status->presence = presence;
496
497 status->attr_values =
498 g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
499 (GDestroyNotify)gaim_value_destroy);
500
501 for (l = gaim_status_type_get_attrs(status_type); l != NULL; l = l->next)
502 {
503 GaimStatusAttr *attr = (GaimStatusAttr *)l->data;
504 GaimValue *value = gaim_status_attr_get_value_type(attr);
505 GaimValue *new_value = gaim_value_dup(value);
506
507 g_hash_table_insert(status->attr_values,
508 g_strdup(gaim_status_attr_get_id(attr)), new_value);
509 }
510
511 return status;
512 }
513
514 void
515 gaim_status_destroy(GaimStatus *status)
516 {
517 g_return_if_fail(status != NULL);
518
519 gaim_status_set_active(status, FALSE);
520
521 g_hash_table_destroy(status->attr_values);
522
523 g_free(status);
524 }
67 525
68 static void 526 static void
69 free_parser_data(gpointer user_data) 527 notify_buddy_status_update(GaimBuddy *buddy, GaimPresence *presence,
70 { 528 GaimStatus *old_status, GaimStatus *new_status)
71 StatusParserData *data = user_data; 529 {
72 530 GaimBlistUiOps *ops = gaim_blist_get_ui_ops();
73 if (data->buffer != NULL) 531
74 g_string_free(data->buffer, TRUE); 532 if (gaim_prefs_get_bool("/core/logging/log_system") &&
75 533 gaim_prefs_get_bool("/core/logging/log_away_state"))
76 g_free(data); 534 {
77 } 535 time_t current_time = time(NULL);
78 536 const char *buddy_alias = gaim_buddy_get_alias(buddy);
79 static void gaim_status_write(FILE *fp, struct away_message *am) 537 char *tmp = NULL;
80 { 538
81 char *esc = NULL; 539 if (!gaim_status_is_available(old_status) &&
82 540 gaim_status_is_available(new_status))
83 esc = g_markup_escape_text(am->name, -1); 541 {
84 fprintf(fp, "\t<status name=\"%s\">\n", esc); 542 tmp = g_strdup_printf(_("%s came back"), buddy_alias);
85 g_free(esc); 543 }
86 544 else if (gaim_status_is_available(old_status) &&
87 fprintf(fp, "\t\t<state>away</state>\n"); 545 !gaim_status_is_available(new_status))
88 546 {
89 esc = g_markup_escape_text(am->message, -1); 547 tmp = g_strdup_printf(_("%s went away"), buddy_alias);
90 fprintf(fp, "\t\t<message>%s</message>\n", esc); 548 }
91 g_free(esc); 549
92 550 if (tmp != NULL)
93 fprintf(fp, "\t</status>\n"); 551 {
94 } 552 GaimLog *log = gaim_account_get_log(buddy->account);
95 553
96 static gboolean 554 gaim_log_write(log, GAIM_MESSAGE_SYSTEM, buddy_alias,
97 status_save_cb(gpointer unused) 555 current_time, tmp);
98 { 556 g_free(tmp);
99 gaim_status_sync(); 557 }
100 status_save_timer = 0; 558 }
559
560 if (ops != NULL && ops->status_changed != NULL)
561 ops->status_changed(buddy, new_status);
562 }
563
564 static void
565 notify_status_update(GaimPresence *presence, GaimStatus *old_status,
566 GaimStatus *new_status)
567 {
568 GaimPresenceContext context = gaim_presence_get_context(presence);
569
570 if (context == GAIM_PRESENCE_CONTEXT_ACCOUNT)
571 {
572 GaimAccountUiOps *ops = gaim_accounts_get_ui_ops();
573
574 if (ops != NULL && ops->status_changed != NULL)
575 {
576 ops->status_changed(gaim_presence_get_account(presence),
577 new_status);
578 }
579 }
580 else if (context == GAIM_PRESENCE_CONTEXT_CONV)
581 {
582 /* TODO */
583 #if 0
584 GaimConversationUiOps *ops;
585 GaimConversation *conv;
586
587 conv = gaim_status_get_conversation(new_status);
588 #endif
589 }
590 else if (context == GAIM_PRESENCE_CONTEXT_BUDDY)
591 {
592 const GList *l;
593
594 for (l = gaim_presence_get_buddies(presence); l != NULL; l = l->next)
595 {
596 notify_buddy_status_update((GaimBuddy *)l->data, presence,
597 old_status, new_status);
598 }
599 }
600 }
601
602 void
603 gaim_status_set_active(GaimStatus *status, gboolean active)
604 {
605 GaimStatusType *status_type;
606 GaimPresence *presence;
607 GaimStatus *old_status;
608
609 g_return_if_fail(status != NULL);
610
611 if (status->active == active)
612 return;
613
614 status_type = gaim_status_get_type(status);
615
616 if (!active && gaim_status_type_is_independent(status_type))
617 {
618 gaim_debug(GAIM_DEBUG_ERROR, "status",
619 "Cannot deactivate an exclusive status (%s).\n",
620 gaim_status_type_get_id(status_type));
621 return;
622 }
623
624 presence = gaim_status_get_presence(status);
625 old_status = gaim_presence_get_active_status(presence);
626
627 if (!gaim_status_type_is_independent(status_type))
628 {
629 const GList *l;
630
631 for (l = gaim_presence_get_statuses(presence);
632 l != NULL;
633 l = l->next)
634 {
635 GaimStatus *temp_status = (GaimStatus *)l->data;
636 GaimStatusType *temp_type;
637
638 if (temp_status == status)
639 continue;
640
641 temp_type = gaim_status_get_type(temp_status);
642
643 if (gaim_status_type_is_independent(temp_type))
644 continue;
645
646 if (gaim_status_is_active(temp_status))
647 {
648 /*
649 * Since we don't want an infinite loop, we have to set
650 * the active variable ourself.
651 */
652 temp_status->active = FALSE;
653
654 notify_status_update(presence, old_status, temp_status);
655
656 break;
657 }
658 }
659 }
660
661 status->active = active;
662
663 notify_status_update(presence, old_status, status);
664 }
665
666 void
667 gaim_status_set_attr_boolean(GaimStatus *status, const char *id,
668 gboolean value)
669 {
670 GaimStatusType *status_type;
671 GaimStatusAttr *attr;
672 GaimValue *attr_value;
673
674 g_return_if_fail(status != NULL);
675 g_return_if_fail(id != NULL);
676
677 status_type = gaim_status_get_type(status);
678
679 /* Make sure this attribute exists. */
680 attr = gaim_status_type_get_attr(status_type, id);
681 g_return_if_fail(attr != NULL);
682
683 attr_value = gaim_status_attr_get_value_type(attr);
684 g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_BOOLEAN);
685
686 gaim_value_set_boolean(attr_value, value);
687 }
688
689 void
690 gaim_status_set_attr_int(GaimStatus *status, const char *id, int value)
691 {
692 GaimStatusType *status_type;
693 GaimStatusAttr *attr;
694 GaimValue *attr_value;
695
696 g_return_if_fail(status != NULL);
697 g_return_if_fail(id != NULL);
698
699 status_type = gaim_status_get_type(status);
700
701 /* Make sure this attribute exists. */
702 attr = gaim_status_type_get_attr(status_type, id);
703 g_return_if_fail(attr != NULL);
704
705 attr_value = gaim_status_attr_get_value_type(attr);
706 g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_INT);
707
708 gaim_value_set_int(attr_value, value);
709 }
710
711 void
712 gaim_status_set_attr_string(GaimStatus *status, const char *id,
713 const char *value)
714 {
715 GaimStatusType *status_type;
716 GaimStatusAttr *attr;
717 GaimValue *attr_value;
718
719 g_return_if_fail(status != NULL);
720 g_return_if_fail(id != NULL);
721
722 status_type = gaim_status_get_type(status);
723
724 /* Make sure this attribute exists. */
725 attr = gaim_status_type_get_attr(status_type, id);
726 g_return_if_fail(attr != NULL);
727
728 attr_value = gaim_status_attr_get_value_type(attr);
729 g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_STRING);
730
731 gaim_value_set_string(attr_value, value);
732 }
733
734 GaimStatusType *
735 gaim_status_get_type(const GaimStatus *status)
736 {
737 g_return_val_if_fail(status != NULL, NULL);
738
739 return status->type;
740 }
741
742 GaimPresence *
743 gaim_status_get_presence(const GaimStatus *status)
744 {
745 g_return_val_if_fail(status != NULL, NULL);
746
747 return status->presence;
748 }
749
750 const char *
751 gaim_status_get_id(const GaimStatus *status)
752 {
753 g_return_val_if_fail(status != NULL, NULL);
754
755 return gaim_status_type_get_id(gaim_status_get_type(status));
756 }
757
758 const char *
759 gaim_status_get_name(const GaimStatus *status)
760 {
761 g_return_val_if_fail(status != NULL, NULL);
762
763 return gaim_status_type_get_name(gaim_status_get_type(status));
764 }
765
766 gboolean
767 gaim_status_is_independent(const GaimStatus *status)
768 {
769 g_return_val_if_fail(status != NULL, FALSE);
770
771 return gaim_status_type_is_independent(gaim_status_get_type(status));
772 }
773
774 gboolean
775 gaim_status_is_available(const GaimStatus *status)
776 {
777 g_return_val_if_fail(status != NULL, FALSE);
778
779 return gaim_status_type_is_available(gaim_status_get_type(status));
780 }
781
782 gboolean
783 gaim_status_is_active(const GaimStatus *status)
784 {
785 g_return_val_if_fail(status != NULL, FALSE);
786
787 return status->active;
788 }
789
790 GaimValue *
791 gaim_status_get_attr_value(const GaimStatus *status, const char *id)
792 {
793 GaimStatusType *status_type;
794 GaimStatusAttr *attr;
795
796 g_return_val_if_fail(status != NULL, NULL);
797 g_return_val_if_fail(id != NULL, NULL);
798
799 status_type = gaim_status_get_type(status);
800
801 /* Make sure this attribute exists. */
802 attr = gaim_status_type_get_attr(status_type, id);
803 g_return_val_if_fail(attr != NULL, NULL);
804
805 return (GaimValue *)g_hash_table_lookup(status->attr_values, id);
806 }
807
808 gboolean
809 gaim_status_get_attr_boolean(const GaimStatus *status, const char *id)
810 {
811 const GaimValue *value;
812
813 g_return_val_if_fail(status != NULL, FALSE);
814 g_return_val_if_fail(id != NULL, FALSE);
815
816 if ((value = gaim_status_get_attr_value(status, id)) == NULL)
817 return FALSE;
818
819 g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_STRING, FALSE);
820
821 return gaim_value_get_boolean(value);
822 }
823
824 int
825 gaim_status_get_attr_int(const GaimStatus *status, const char *id)
826 {
827 const GaimValue *value;
828
829 g_return_val_if_fail(status != NULL, FALSE);
830 g_return_val_if_fail(id != NULL, FALSE);
831
832 if ((value = gaim_status_get_attr_value(status, id)) == NULL)
833 return FALSE;
834
835 g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_INT, 0);
836
837 return gaim_value_get_int(value);
838 }
839
840 const char *
841 gaim_status_get_attr_string(const GaimStatus *status, const char *id)
842 {
843 const GaimValue *value;
844
845 g_return_val_if_fail(status != NULL, FALSE);
846 g_return_val_if_fail(id != NULL, FALSE);
847
848 if ((value = gaim_status_get_attr_value(status, id)) == NULL)
849 return FALSE;
850
851 g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_STRING, NULL);
852
853 return gaim_value_get_string(value);
854 }
855
856 gint
857 gaim_status_compare(const GaimStatus *status1, const GaimStatus *status2)
858 {
859 GaimStatusType *type1, *type2;
860 int score1 = 0, score2 = 0;
861
862 if ((status1 == NULL && status2 == NULL) ||
863 (status1 == status2))
864 {
865 return 0;
866 }
867 else if (status1 == NULL)
868 return 1;
869 else if (status2 == NULL)
870 return -1;
871
872 type1 = gaim_status_get_type(status1);
873 type2 = gaim_status_get_type(status2);
874
875 if (gaim_status_is_active(status1))
876 score1 = primitive_scores[gaim_status_type_get_primitive(type1)];
877
878 if (gaim_status_is_active(status2))
879 score2 = primitive_scores[gaim_status_type_get_primitive(type2)];
880
881 if (score1 > score2)
882 return -1;
883 else if (score1 < score2)
884 return 1;
885
886 return 0;
887 }
888
889
890 /**************************************************************************
891 * GaimPresence API
892 **************************************************************************/
893 GaimPresence *
894 gaim_presence_new(GaimPresenceContext context)
895 {
896 GaimPresence *presence;
897
898 g_return_val_if_fail(context != GAIM_PRESENCE_CONTEXT_UNSET, NULL);
899
900 presence = g_new0(GaimPresence, 1);
901
902 presence->context = context;
903
904 presence->status_table =
905 g_hash_table_new_full(g_str_hash, g_str_equal,
906 g_free, (GFreeFunc)gaim_status_destroy);
907
908 return presence;
909 }
910
911 GaimPresence *
912 gaim_presence_new_for_account(GaimAccount *account)
913 {
914 GaimPresence *presence;
915
916 g_return_val_if_fail(account != NULL, NULL);
917
918 presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_ACCOUNT);
919
920 presence->u.account = account;
921
922 return presence;
923 }
924
925 GaimPresence *
926 gaim_presence_new_for_conv(GaimConversation *conv)
927 {
928 GaimPresence *presence;
929
930 g_return_val_if_fail(conv != NULL, NULL);
931
932 presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_CONV);
933
934 presence->u.chat.conv = conv;
935
936 return presence;
937 }
938
939 GaimPresence *
940 gaim_presence_new_for_buddy(GaimBuddy *buddy)
941 {
942 GaimPresence *presence;
943 GaimStatusBuddyKey *key;
944
945 g_return_val_if_fail(buddy != NULL, NULL);
946
947 key = g_new0(GaimStatusBuddyKey, 1);
948 key->account = buddy->account;
949 key->name = g_strdup(buddy->name);
950
951 if ((presence = g_hash_table_lookup(buddy_presences, key)) == NULL)
952 {
953 presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_BUDDY);
954
955 presence->u.buddy.name = g_strdup(buddy->name);
956 presence->u.buddy.account = buddy->account;
957
958 g_hash_table_insert(buddy_presences, key, presence);
959 }
960 else
961 {
962 g_free(key->name);
963 g_free(key);
964 }
965
966 presence->u.buddy.ref_count++;
967 presence->u.buddy.buddies = g_list_append(presence->u.buddy.buddies,
968 buddy);
969
970 return presence;
971 }
972
973 void
974 gaim_presence_destroy(GaimPresence *presence)
975 {
976 g_return_if_fail(presence != NULL);
977
978 if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY)
979 {
980 GaimStatusBuddyKey key;
981
982 presence->u.buddy.ref_count--;
983
984 g_return_if_fail(presence->u.buddy.ref_count == 0);
985
986 key.account = presence->u.buddy.account;
987 key.name = presence->u.buddy.name;
988
989 g_hash_table_remove(buddy_presences, &key);
990
991 if (presence->u.buddy.name != NULL)
992 g_free(presence->u.buddy.name);
993 }
994 else if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_CONV)
995 {
996 if (presence->u.chat.user != NULL)
997 g_free(presence->u.chat.user);
998 }
999
1000 if (presence->statuses != NULL)
1001 g_list_free(presence->statuses);
1002
1003 g_hash_table_destroy(presence->status_table);
1004
1005 g_free(presence);
1006 }
1007
1008 void
1009 gaim_presence_remove_buddy(GaimPresence *presence, GaimBuddy *buddy)
1010 {
1011 g_return_if_fail(presence != NULL);
1012 g_return_if_fail(buddy != NULL);
1013 g_return_if_fail(gaim_presence_get_context(presence) ==
1014 GAIM_PRESENCE_CONTEXT_BUDDY);
1015
1016 if (g_list_find(presence->u.buddy.buddies, buddy) != NULL)
1017 {
1018 presence->u.buddy.buddies = g_list_remove(presence->u.buddy.buddies,
1019 buddy);
1020 presence->u.buddy.ref_count--;
1021 }
1022 }
1023
1024 void
1025 gaim_presence_add_status(GaimPresence *presence, GaimStatus *status)
1026 {
1027 g_return_if_fail(presence != NULL);
1028 g_return_if_fail(status != NULL);
1029
1030 presence->statuses = g_list_append(presence->statuses, status);
1031
1032 g_hash_table_insert(presence->status_table,
1033 g_strdup(gaim_status_get_id(status)), status);
1034 }
1035
1036 void
1037 gaim_presence_add_presence(GaimPresence *presence, const GList *source_list)
1038 {
1039 const GList *l;
1040
1041 g_return_if_fail(presence != NULL);
1042 g_return_if_fail(source_list != NULL);
1043
1044 for (l = source_list; l != NULL; l = l->next)
1045 gaim_presence_add_status(presence, (GaimStatus *)l->data);
1046 }
1047
1048 void
1049 gaim_presence_set_status_active(GaimPresence *presence, const char *status_id,
1050 gboolean active)
1051 {
1052 GaimStatus *status;
1053
1054 g_return_if_fail(presence != NULL);
1055 g_return_if_fail(status_id != NULL);
1056
1057 status = gaim_presence_get_status(presence, status_id);
1058
1059 g_return_if_fail(status != NULL);
1060
1061 if (!gaim_status_is_independent(status))
1062 {
1063 if (!active)
1064 {
1065 gaim_debug_warning("status",
1066 "Attempted to set a non-independent status "
1067 "(%s) inactive. Only independent statuses "
1068 "can be specifically marked inactive.",
1069 status_id);
1070
1071 return;
1072 }
1073
1074 if (presence->active_status != NULL)
1075 gaim_status_set_active(presence->active_status, FALSE);
1076
1077 presence->active_status = status;
1078 }
1079
1080 gaim_status_set_active(status, active);
1081 }
1082
1083 void
1084 gaim_presence_switch_status(GaimPresence *presence, const char *status_id)
1085 {
1086 GaimStatus *status;
1087
1088 g_return_if_fail(presence != NULL);
1089 g_return_if_fail(status_id != NULL);
1090
1091 status = gaim_presence_get_status(presence, status_id);
1092
1093 g_return_if_fail(status != NULL);
1094
1095 if (gaim_status_is_independent(status))
1096 return;
1097
1098 if (presence->active_status != NULL)
1099 gaim_status_set_active(presence->active_status, FALSE);
1100
1101 gaim_status_set_active(status, TRUE);
1102 }
1103
1104 static void
1105 update_buddy_idle(GaimBuddy *buddy, GaimPresence *presence,
1106 time_t current_time, gboolean old_idle, gboolean idle)
1107 {
1108 GaimBlistUiOps *ops = gaim_get_blist()->ui_ops;
1109
1110 if (!old_idle && idle)
1111 {
1112 gaim_signal_emit(gaim_blist_get_handle(), "buddy-idle", buddy);
1113
1114 if (gaim_prefs_get_bool("/core/logging/log_system") &&
1115 gaim_prefs_get_bool("/core/logging/log_idle_state"))
1116 {
1117 GaimLog *log = gaim_account_get_log(buddy->account);
1118 char *tmp = g_strdup_printf(_("%s became idle"),
1119 gaim_buddy_get_alias(buddy));
1120
1121 gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
1122 gaim_buddy_get_alias(buddy), current_time, tmp);
1123 g_free(tmp);
1124 }
1125 }
1126 else if (old_idle && !idle)
1127 {
1128 gaim_signal_emit(gaim_blist_get_handle(), "buddy-unidle", buddy);
1129
1130 if (gaim_prefs_get_bool("/core/logging/log_system") &&
1131 gaim_prefs_get_bool("/core/logging/log_idle_state"))
1132 {
1133 GaimLog *log = gaim_account_get_log(buddy->account);
1134 char *tmp = g_strdup_printf(_("%s became unidle"),
1135 gaim_buddy_get_alias(buddy));
1136
1137 gaim_log_write(log, GAIM_MESSAGE_SYSTEM,
1138 gaim_buddy_get_alias(buddy), current_time, tmp);
1139 g_free(tmp);
1140 }
1141 }
1142
1143 gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy));
1144
1145 if (ops != NULL && ops->update != NULL)
1146 ops->update(gaim_get_blist(), (GaimBlistNode *)buddy);
1147 }
1148
1149 void
1150 gaim_presence_set_idle(GaimPresence *presence, gboolean idle, time_t idle_time)
1151 {
1152 gboolean old_idle;
1153
1154 g_return_if_fail(presence != NULL);
1155
1156 if (presence->idle == idle && presence->idle_time == idle_time)
1157 return;
1158
1159 old_idle = presence->idle;
1160 presence->idle = idle;
1161 presence->idle_time = (idle ? idle_time : 0);
1162
1163 if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY)
1164 {
1165 const GList *l;
1166 time_t current_time = time(NULL);
1167
1168 for (l = gaim_presence_get_buddies(presence); l != NULL; l = l->next)
1169 {
1170 update_buddy_idle((GaimBuddy *)l->data, presence, current_time,
1171 old_idle, idle);
1172 }
1173 }
1174 }
1175
1176 void
1177 gaim_presence_set_warning_level(GaimPresence *presence, unsigned int level)
1178 {
1179 g_return_if_fail(presence != NULL);
1180 g_return_if_fail(level <= 100);
1181
1182 if (presence->warning_level == level)
1183 return;
1184
1185 presence->warning_level = level;
1186
1187 if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY)
1188 {
1189 GaimBlistUiOps *ops = gaim_get_blist()->ui_ops;
1190
1191 if (ops != NULL && ops->update != NULL)
1192 {
1193 const GList *l;
1194
1195 for (l = gaim_presence_get_buddies(presence);
1196 l != NULL;
1197 l = l->next)
1198 {
1199 ops->update(gaim_get_blist(), (GaimBlistNode *)l->data);
1200 }
1201 }
1202 }
1203 }
1204
1205 GaimPresenceContext
1206 gaim_presence_get_context(const GaimPresence *presence)
1207 {
1208 g_return_val_if_fail(presence != NULL, GAIM_PRESENCE_CONTEXT_UNSET);
1209
1210 return presence->context;
1211 }
1212
1213 GaimAccount *
1214 gaim_presence_get_account(const GaimPresence *presence)
1215 {
1216 GaimPresenceContext context;
1217
1218 g_return_val_if_fail(presence != NULL, NULL);
1219
1220 context = gaim_presence_get_context(presence);
1221
1222 g_return_val_if_fail(context == GAIM_PRESENCE_CONTEXT_ACCOUNT ||
1223 context == GAIM_PRESENCE_CONTEXT_BUDDY, NULL);
1224
1225 return presence->u.account;
1226 }
1227
1228 GaimConversation *
1229 gaim_presence_get_conversation(const GaimPresence *presence)
1230 {
1231 g_return_val_if_fail(presence != NULL, NULL);
1232 g_return_val_if_fail(gaim_presence_get_context(presence) ==
1233 GAIM_PRESENCE_CONTEXT_CONV, NULL);
1234
1235 return presence->u.chat.conv;
1236 }
1237
1238 const char *
1239 gaim_presence_get_chat_user(const GaimPresence *presence)
1240 {
1241 g_return_val_if_fail(presence != NULL, NULL);
1242 g_return_val_if_fail(gaim_presence_get_context(presence) ==
1243 GAIM_PRESENCE_CONTEXT_CONV, NULL);
1244
1245 return presence->u.chat.user;
1246 }
1247
1248 const GList *
1249 gaim_presence_get_buddies(const GaimPresence *presence)
1250 {
1251 g_return_val_if_fail(presence != NULL, NULL);
1252 g_return_val_if_fail(gaim_presence_get_context(presence) ==
1253 GAIM_PRESENCE_CONTEXT_BUDDY, NULL);
1254
1255 return presence->u.buddy.buddies;
1256 }
1257
1258 const GList *
1259 gaim_presence_get_statuses(const GaimPresence *presence)
1260 {
1261 g_return_val_if_fail(presence != NULL, NULL);
1262
1263 return presence->statuses;
1264 }
1265
1266 GaimStatus *
1267 gaim_presence_get_status(const GaimPresence *presence, const char *status_id)
1268 {
1269 GaimStatus *status;
1270
1271 g_return_val_if_fail(presence != NULL, NULL);
1272 g_return_val_if_fail(status_id != NULL, NULL);
1273
1274 status = (GaimStatus *)g_hash_table_lookup(presence->status_table,
1275 status_id);
1276
1277 return status;
1278 }
1279
1280 GaimStatus *
1281 gaim_presence_get_active_status(const GaimPresence *presence)
1282 {
1283 g_return_val_if_fail(presence != NULL, NULL);
1284
1285 return presence->active_status;
1286 }
1287
1288 gboolean
1289 gaim_presence_is_available(const GaimPresence *presence)
1290 {
1291 GaimStatus *status;
1292
1293 g_return_val_if_fail(presence != NULL, FALSE);
1294
1295 status = gaim_presence_get_active_status(presence);
1296
1297 return ((status != NULL && gaim_status_is_available(status)) &&
1298 !gaim_presence_is_idle(presence));
1299 }
1300
1301 gboolean
1302 gaim_presence_is_online(const GaimPresence *presence)
1303 {
1304 GaimStatus *status;
1305 GaimStatusPrimitive primitive;
1306
1307 g_return_val_if_fail(presence != NULL, FALSE);
1308
1309 if ((status = gaim_presence_get_active_status(presence)) == NULL)
1310 return FALSE;
1311
1312 primitive = gaim_status_type_get_primitive(gaim_status_get_type(status));
1313
1314 return (primitive != GAIM_STATUS_UNSET &&
1315 primitive != GAIM_STATUS_OFFLINE);
1316 }
1317
1318 gboolean
1319 gaim_presence_is_status_active(const GaimPresence *presence,
1320 const char *status_id)
1321 {
1322 GaimStatus *status;
1323
1324 g_return_val_if_fail(presence != NULL, FALSE);
1325 g_return_val_if_fail(status_id != NULL, FALSE);
1326
1327 status = gaim_presence_get_status(presence, status_id);
1328
1329 return (status != NULL && gaim_status_is_active(status));
1330 }
1331
1332 gboolean
1333 gaim_presence_is_status_primitive_active(const GaimPresence *presence,
1334 GaimStatusPrimitive primitive)
1335 {
1336 GaimStatus *status;
1337 GaimStatusType *status_type;
1338
1339 g_return_val_if_fail(presence != NULL, FALSE);
1340 g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, FALSE);
1341
1342 status = gaim_presence_get_active_status(presence);
1343 status_type = gaim_status_get_type(status);
1344
1345 if (gaim_status_type_get_primitive(status_type) == primitive)
1346 return TRUE;
101 1347
102 return FALSE; 1348 return FALSE;
103 } 1349 }
104 1350
1351 gboolean
1352 gaim_presence_is_idle(const GaimPresence *presence)
1353 {
1354 g_return_val_if_fail(presence != NULL, FALSE);
1355
1356 return presence->idle;
1357 }
1358
1359 time_t
1360 gaim_presence_get_idle_time(const GaimPresence *presence)
1361 {
1362 g_return_val_if_fail(presence != NULL, 0);
1363
1364 return presence->idle_time;
1365 }
1366
1367 unsigned int
1368 gaim_presence_get_warning_level(const GaimPresence *presence)
1369 {
1370 g_return_val_if_fail(presence != NULL, 0);
1371
1372 return presence->warning_level;
1373 }
1374
1375 gint
1376 gaim_presence_compare(const GaimPresence *presence1,
1377 const GaimPresence *presence2)
1378 {
1379 gboolean idle1, idle2;
1380 size_t idle_time_1, idle_time_2;
1381 int score1 = 0, score2 = 0;
1382 const GList *l;
1383
1384 if ((presence1 == NULL && presence2 == NULL) || (presence1 == presence2))
1385 return 0;
1386 else if (presence1 == NULL)
1387 return -1;
1388 else if (presence2 == NULL)
1389 return 1;
1390
1391 /* Compute the score of the first set of statuses. */
1392 for (l = gaim_presence_get_statuses(presence1); l != NULL; l = l->next)
1393 {
1394 GaimStatus *status = (GaimStatus *)l->data;
1395 GaimStatusType *type = gaim_status_get_type(status);
1396
1397 if (gaim_status_is_active(status))
1398 score1 += primitive_scores[gaim_status_type_get_primitive(type)];
1399 }
1400
1401 /* Compute the score of the second set of statuses. */
1402 for (l = gaim_presence_get_statuses(presence1); l != NULL; l = l->next)
1403 {
1404 GaimStatus *status = (GaimStatus *)l->data;
1405 GaimStatusType *type = gaim_status_get_type(status);
1406
1407 if (gaim_status_is_active(status))
1408 score2 += primitive_scores[gaim_status_type_get_primitive(type)];
1409 }
1410
1411 idle1 = gaim_presence_is_idle(presence1);
1412 idle2 = gaim_presence_is_idle(presence2);
1413
1414 if (idle1)
1415 score1 += primitive_scores[SCORE_IDLE];
1416
1417 if (idle2)
1418 score2 += primitive_scores[SCORE_IDLE];
1419
1420 idle_time_1 = gaim_presence_get_idle_time(presence1);
1421 idle_time_2 = gaim_presence_get_idle_time(presence2);
1422
1423 if (idle_time_1 > idle_time_2)
1424 score1 += primitive_scores[SCORE_IDLE_TIME];
1425 else if (idle_time_1 < idle_time_2)
1426 score2 += primitive_scores[SCORE_IDLE_TIME];
1427
1428 if (score1 < score2)
1429 return 1;
1430 else if (score1 > score2)
1431 return -1;
1432
1433 return 0;
1434 }
1435
1436
1437 /**************************************************************************
1438 * Status subsystem
1439 **************************************************************************/
105 static void 1440 static void
106 schedule_status_save() 1441 score_pref_changed_cb(const char *name, GaimPrefType type, gpointer value,
107 { 1442 gpointer data)
108 if (!status_save_timer) 1443 {
109 status_save_timer = gaim_timeout_add(5000, status_save_cb, NULL); 1444 int index = GPOINTER_TO_INT(data);
110 } 1445
111 1446 primitive_scores[index] = GPOINTER_TO_INT(value);
112 static void 1447 }
113 start_element_handler(GMarkupParseContext *context, 1448
114 const gchar *element_name, 1449 void
115 const gchar **attribute_names, 1450 gaim_statuses_init(void)
116 const gchar **attribute_values, 1451 {
117 gpointer user_data, GError **error) 1452 gaim_prefs_add_none("/core/status");
118 { 1453 gaim_prefs_add_none("/core/status/scores");
119 const char *value; 1454
120 StatusParserData *data = user_data; 1455 gaim_prefs_add_int("/core/status/scores/offline",
121 GHashTable *atts; 1456 primitive_scores[GAIM_STATUS_OFFLINE]);
122 int i; 1457 gaim_prefs_add_int("/core/status/scores/available",
123 1458 primitive_scores[GAIM_STATUS_AVAILABLE]);
124 atts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 1459 gaim_prefs_add_int("/core/status/scores/hidden",
125 1460 primitive_scores[GAIM_STATUS_HIDDEN]);
126 for (i = 0; attribute_names[i] != NULL; i++) { 1461 gaim_prefs_add_int("/core/status/scores/away",
127 g_hash_table_insert(atts, g_strdup(attribute_names[i]), 1462 primitive_scores[GAIM_STATUS_AWAY]);
128 g_strdup(attribute_values[i])); 1463 gaim_prefs_add_int("/core/status/scores/extended_away",
129 } 1464 primitive_scores[GAIM_STATUS_EXTENDED_AWAY]);
130 1465 gaim_prefs_add_int("/core/status/scores/idle",
131 if (data->buffer != NULL) { 1466 primitive_scores[SCORE_IDLE]);
132 g_string_free(data->buffer, TRUE); 1467
133 data->buffer = NULL; 1468 gaim_prefs_connect_callback("/core/status/scores/offline",
134 } 1469 score_pref_changed_cb,
135 1470 GINT_TO_POINTER(GAIM_STATUS_OFFLINE));
136 if (!strcmp(element_name, "status")) { 1471 gaim_prefs_connect_callback("/core/status/scores/available",
137 data->tag = TAG_STATUS; 1472 score_pref_changed_cb,
138 if ((value = g_hash_table_lookup(atts, "name")) != NULL) { 1473 GINT_TO_POINTER(GAIM_STATUS_AVAILABLE));
139 data->am = g_new0(struct away_message, 1); 1474 gaim_prefs_connect_callback("/core/status/scores/hidden",
140 g_snprintf(data->am->name, sizeof(data->am->name), "%s", value); 1475 score_pref_changed_cb,
141 away_messages = g_slist_append(away_messages, data->am); 1476 GINT_TO_POINTER(GAIM_STATUS_HIDDEN));
142 } 1477 gaim_prefs_connect_callback("/core/status/scores/away",
143 } else if (!strcmp(element_name, "message")) { 1478 score_pref_changed_cb,
144 data->tag = TAG_MESSAGE; 1479 GINT_TO_POINTER(GAIM_STATUS_AWAY));
145 1480 gaim_prefs_connect_callback("/core/status/scores/extended_away",
146 } 1481 score_pref_changed_cb,
147 1482 GINT_TO_POINTER(GAIM_STATUS_EXTENDED_AWAY));
148 g_hash_table_destroy(atts); 1483 gaim_prefs_connect_callback("/core/status/scores/idle",
149 } 1484 score_pref_changed_cb,
150 1485 GINT_TO_POINTER(SCORE_IDLE));
151 static void 1486 }
152 end_element_handler(GMarkupParseContext *context, const gchar *element_name, 1487
153 gpointer user_data, GError **error) 1488 void
154 { 1489 gaim_statuses_uninit(void)
155 StatusParserData *data = user_data; 1490 {
156 gchar *buffer; 1491 }
157 1492
158 if (data->buffer == NULL) 1493 void
159 return; 1494 gaim_statuses_sync(void)
160 1495 {
161 buffer = g_string_free(data->buffer, FALSE); 1496 }
162 data->buffer = NULL; 1497
163 1498 void
164 if (data->tag == TAG_MESSAGE) { 1499 gaim_statuses_load(void)
165 if (*buffer != '\0') 1500 {
166 g_snprintf(data->am->message, sizeof(data->am->message), "%s", buffer); 1501 }
167 }
168
169 data->tag = TAG_NONE;
170
171 g_free(buffer);
172 }
173
174 static void
175 text_handler(GMarkupParseContext *context, const gchar *text,
176 gsize text_len, gpointer user_data, GError **error)
177 {
178 StatusParserData *data = user_data;
179
180 if (data->buffer == NULL)
181 data->buffer = g_string_new_len(text, text_len);
182 else
183 g_string_append_len(data->buffer, text, text_len);
184 }
185
186 static GMarkupParser status_parser =
187 {
188 start_element_handler,
189 end_element_handler,
190 text_handler,
191 NULL,
192 NULL
193 };
194
195 void gaim_status_sync()
196 {
197 FILE *fp;
198 const char *user_dir = gaim_user_dir();
199 char *filename, *filename_real;
200
201 if (!status_loaded) {
202 gaim_debug(GAIM_DEBUG_WARNING, "status", "Writing status to disk.\n");
203 schedule_status_save();
204 return;
205 }
206
207 if (user_dir == NULL)
208 return;
209
210 gaim_debug(GAIM_DEBUG_INFO, "status", "Saving statuses to disk\n");
211
212 fp = fopen(user_dir, "r");
213
214 if (fp == NULL)
215 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR);
216 else
217 fclose(fp);
218
219 filename = g_build_filename(user_dir, "status.xml.save", NULL);
220
221 if ((fp = fopen(filename, "w")) != NULL) {
222 GSList *l;
223
224 fprintf(fp, "<?xml version='1.0' encoding='UTF-8' ?>\n\n");
225 fprintf(fp, "<statuses>\n");
226
227 for (l = away_messages; l != NULL; l = l->next)
228 gaim_status_write(fp, l->data);
229
230 fprintf(fp, "</statuses>\n");
231
232 fclose(fp);
233 chmod(filename, S_IRUSR | S_IWUSR);
234 }
235 else {
236 gaim_debug(GAIM_DEBUG_ERROR, "status", "Unable to write %s\n",
237 filename);
238 g_free(filename);
239 return;
240 }
241
242 filename_real = g_build_filename(user_dir, "status.xml", NULL);
243
244 if (rename(filename, filename_real) < 0) {
245 gaim_debug(GAIM_DEBUG_ERROR, "status", "Error renaming %s to %s\n",
246 filename, filename_real);
247 }
248
249 g_free(filename);
250 g_free(filename_real);
251
252 }
253
254 void gaim_status_load()
255 {
256 gchar *filename = g_build_filename(gaim_user_dir(), "status.xml", NULL);
257 gchar *contents = NULL;
258 gsize length;
259 GMarkupParseContext *context;
260 GError *error = NULL;
261 StatusParserData *parser_data;
262
263 if (filename == NULL) {
264 status_loaded = TRUE;
265 return;
266 }
267
268 if (!g_file_get_contents(filename, &contents, &length, &error)) {
269 gaim_debug(GAIM_DEBUG_ERROR, "status",
270 "Error reading statuses: %s\n", error->message);
271 g_error_free(error);
272 g_free(filename);
273 status_loaded = TRUE;
274 if (!away_messages) {
275 struct away_message *a = g_new0(struct away_message, 1);
276 g_snprintf(a->name, sizeof(a->name), _("Slightly less boring default"));
277 g_snprintf(a->message, sizeof(a->message), "%s", _(BORING_DEFAULT_AWAY_MSG));
278 away_messages = g_slist_append(away_messages, a);
279 }
280 return;
281 }
282
283 parser_data = g_new0(StatusParserData, 1);
284
285 context = g_markup_parse_context_new(&status_parser, 0,
286 parser_data, free_parser_data);
287
288 if (!g_markup_parse_context_parse(context, contents, length, NULL)) {
289 g_markup_parse_context_free(context);
290 g_free(contents);
291 g_free(filename);
292 status_loaded = TRUE;
293 return;
294 }
295
296 if (!g_markup_parse_context_end_parse(context, NULL)) {
297 gaim_debug(GAIM_DEBUG_ERROR, "status", "Error parsing %s\n",
298 filename);
299 g_markup_parse_context_free(context);
300 g_free(contents);
301 g_free(filename);
302 status_loaded = TRUE;
303 return;
304 }
305
306 g_markup_parse_context_free(context);
307 g_free(contents);
308 g_free(filename);
309 status_loaded = TRUE;
310 return;
311 }

mercurial