# HG changeset patch # User Luke Schierer # Date 1094272025 0 # Node ID ced29c7b396cb63ecc1c195e369d193ab8799b42 # Parent b13013595c084d1952f64a093c6e3e97269ea880 [gaim-migrate @ 10845] (00:25:10) LSchiere: datallah: commit message? (00:25:40) datallah: LSchiere: nah.. nothing comes to me datallah undertook the heroic effort of merging in all the .rejs and fixing things up from the unclean merge of the status rewrite committer: Tailor Script diff -r b13013595c08 -r ced29c7b396c src/Makefile.mingw --- a/src/Makefile.mingw Sat Sep 04 03:33:16 2004 +0000 +++ b/src/Makefile.mingw Sat Sep 04 04:27:05 2004 +0000 @@ -201,7 +201,7 @@ all: $(TARGET).exe $(TARGET).dll -install: +install: all cp $(GAIM_SRC)/gaim.exe $(GAIM_SRC)/gaim.dll $(GAIM_INSTALL_DIR) $(IDLETRACK_TOP)/idletrack.dll: diff -r b13013595c08 -r ced29c7b396c src/blist.c --- a/src/blist.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/blist.c Sat Sep 04 04:27:05 2004 +0000 @@ -121,41 +121,48 @@ } } -static void gaim_contact_compute_priority_buddy(GaimContact *contact) +void gaim_contact_compute_priority_buddy(GaimContact *contact) { GaimBlistNode *bnode; - int contact_score = INT_MAX; + GaimBuddy *new_priority = NULL; g_return_if_fail(contact != NULL); contact->priority = NULL; - for (bnode = ((GaimBlistNode*)contact)->child; bnode; bnode = bnode->next) { + for (bnode = ((GaimBlistNode*)contact)->child; + bnode != NULL; + bnode = bnode->next) + { GaimBuddy *buddy; - int score = 0; + GaimPresence *presence; if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) continue; + buddy = (GaimBuddy*)bnode; + if (!gaim_account_is_connected(buddy->account)) continue; - - if (!GAIM_BUDDY_IS_ONLINE(buddy)) - score += gaim_prefs_get_int("/core/contact/offline_score"); - if (buddy->uc & UC_UNAVAILABLE) - score += gaim_prefs_get_int("/core/contact/away_score"); - if (buddy->idle) - score += gaim_prefs_get_int("/core/contact/idle_score"); - - score += gaim_account_get_int(buddy->account, "score", 0); - - if (score < contact_score) { - contact->priority = buddy; - contact_score = score; - } - if (gaim_prefs_get_bool("/core/contact/last_match")) - if (score == contact_score) - contact->priority = buddy; + if (new_priority == NULL) + new_priority = buddy; + else + { + int cmp; + + presence = gaim_buddy_get_presence(buddy); + + cmp = gaim_presence_compare(gaim_buddy_get_presence(new_priority), + gaim_buddy_get_presence(buddy)); + + if (cmp > 0 || (cmp == 0 && + gaim_prefs_get_bool("/core/contact/last_match"))) + { + new_priority = buddy; + } + } } + + contact->priority = new_priority; } static gboolean blist_save_callback(gpointer data) @@ -236,6 +243,7 @@ void gaim_blist_update_buddy_status(GaimBuddy *buddy, int status) { +#if 0 GaimBlistUiOps *ops = gaimbuddylist->ui_ops; int old_status; @@ -256,6 +264,7 @@ if (ops && ops->update) ops->update(gaimbuddylist, (GaimBlistNode*)buddy); +#endif } static gboolean presence_update_timeout_cb(GaimBuddy *buddy) @@ -340,6 +349,7 @@ ops->update(gaimbuddylist, (GaimBlistNode *)buddy); } +#if 0 void gaim_blist_update_buddy_idle(GaimBuddy *buddy, int idle) { GaimBlistUiOps *ops = gaimbuddylist->ui_ops; @@ -355,21 +365,7 @@ if (ops && ops->update) ops->update(gaimbuddylist, (GaimBlistNode *)buddy); } - -void gaim_blist_update_buddy_evil(GaimBuddy *buddy, int warning) -{ - GaimBlistUiOps *ops = gaimbuddylist->ui_ops; - - g_return_if_fail(buddy != NULL); - - if (buddy->evil == warning) - return; - - buddy->evil = warning; - - if (ops && ops->update) - ops->update(gaimbuddylist, (GaimBlistNode *)buddy); -} +#endif void gaim_blist_update_buddy_icon(GaimBuddy *buddy) { @@ -624,9 +620,11 @@ g_return_val_if_fail(screenname != NULL, FALSE); buddy = g_new0(GaimBuddy, 1); - buddy->account = account; - buddy->name = g_strdup(screenname); - buddy->alias = g_strdup(alias); + buddy->account = account; + buddy->name = g_strdup(screenname); + buddy->alias = g_strdup(alias); + buddy->presence = gaim_presence_new_for_buddy(buddy); + gaim_blist_node_initialize_settings((GaimBlistNode *)buddy); ((GaimBlistNode *)buddy)->type = GAIM_BLIST_BUDDY_NODE; @@ -1170,6 +1168,7 @@ for (node = gnode->child; node; node = node->next) ops->update(gaimbuddylist, node); } +#endif } void gaim_blist_remove_contact(GaimContact *contact) @@ -1624,6 +1623,13 @@ return (GaimContact*)((GaimBlistNode*)buddy)->parent; } +GaimPresence *gaim_buddy_get_presence(const GaimBuddy *buddy) +{ + g_return_val_if_fail(buddy != NULL, NULL); + return buddy->presence; +} + + GaimGroup *gaim_find_buddys_group(GaimBuddy *buddy) { g_return_val_if_fail(buddy != NULL, NULL); diff -r b13013595c08 -r ced29c7b396c src/blist.h --- a/src/blist.h Sat Sep 04 03:33:16 2004 +0000 +++ b/src/blist.h Sat Sep 04 04:27:05 2004 +0000 @@ -112,14 +112,13 @@ char *server_alias; /**< The server-specified alias of the buddy. (i.e. MSN "Friendly Names") */ GaimBuddyPresenceState present; /**< This is 0 if the buddy appears offline, 1 if he appears online, and 2 if he has recently signed on */ - int evil; /**< The warning level */ time_t signon; /**< The time the buddy signed on. */ - int idle; /**< The time the buddy has been idle in minutes. */ int uc; /**< This is a cryptic bitmask that makes sense only to the prpl. This will get changed */ void *proto_data; /**< This allows the prpl to associate whatever data it wants with a buddy */ GaimBuddyIcon *icon; /**< The buddy icon. */ GaimAccount *account; /**< the account this buddy belongs to */ guint timer; /**< The timer handle. */ + GaimPresence *presence; }; /** @@ -192,6 +191,7 @@ void (*request_add_chat)(GaimAccount *account, GaimGroup *group, const char *alias, const char *name); void (*request_add_group)(void); + void (*status_changed)(GaimBuddy *buddy, GaimStatus *status); }; diff -r b13013595c08 -r ced29c7b396c src/gtkblist.c --- a/src/gtkblist.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/gtkblist.c Sat Sep 04 04:27:05 2004 +0000 @@ -102,7 +102,9 @@ } GaimGtkJoinChatData; -static GtkWidget *protomenu = NULL, *pluginmenu = NULL; +static GtkWidget *protomenu = NULL; +static GtkWidget *awaymenu = NULL; +static GtkWidget *pluginmenu = NULL; GSList *gaim_gtk_blist_sort_methods = NULL; static struct gaim_gtk_blist_sort_method *current_sort_method = NULL; @@ -2514,14 +2516,20 @@ } } + presence = gaim_buddy_get_presence(b); + + idle = gaim_presence_is_idle(presence); + idle_secs = gaim_presence_get_idle_time(presence); + warning_level = gaim_presence_get_warning_level(presence); + if (!statustext && !GAIM_BUDDY_IS_ONLINE(b)) statustext = g_strdup(_("\nStatus: Offline")); if (b->signon > 0) loggedin = gaim_str_seconds_to_string(time(NULL) - b->signon); - if (b->idle > 0) - idletime = gaim_str_seconds_to_string(time(NULL) - b->idle); + if (idle && idle_secs > 0) + idletime = gaim_str_seconds_to_string(time(NULL) - idle_secs); if(b->alias && b->alias[0]) aliastext = g_markup_escape_text(b->alias, -1); @@ -2551,8 +2559,9 @@ aliastext ? _("\nAlias:") : "", aliastext ? aliastext : "", nicktext ? _("\nNickname:") : "", nicktext ? nicktext : "", loggedin ? _("\nLogged In:") : "", loggedin ? loggedin : "", - idletime ? _("\nIdle:") : "", idletime ? idletime : "", - b->evil ? _("\nWarned:") : "", b->evil ? warning : "", + idle ? (idle_secs > 0 ? _("\nIdle:") : _("\nIdle")) : "", + idletime ? idletime : "", + warning_level ? _("\nWarned:") : "", warning_level ? warning : "", statustext ? statustext : "", !g_ascii_strcasecmp(b->name, "robflynn") ? _("\nDescription: Spooky") : !g_ascii_strcasecmp(b->name, "seanegn") ? _("\nStatus: Awesome") : diff -r b13013595c08 -r ced29c7b396c src/gtkdialogs.c --- a/src/gtkdialogs.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/gtkdialogs.c Sat Sep 04 04:27:05 2004 +0000 @@ -863,7 +863,6 @@ g_free(text); } -#endif /* 0 */ static void gaim_gtkdialogs_remove_chat_cb(GaimChat *chat) diff -r b13013595c08 -r ced29c7b396c src/gtkpounce.c --- a/src/gtkpounce.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/gtkpounce.c Sat Sep 04 04:27:05 2004 +0000 @@ -758,8 +758,9 @@ else { gboolean default_set = FALSE; + GaimPresence *presence = gaim_buddy_get_presence(buddy); - if (buddy->idle) + if (gaim_presence_is_idle(presence)) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(dialog->idle_return), TRUE); @@ -767,7 +768,7 @@ default_set = TRUE; } - if (buddy->uc & UC_UNAVAILABLE) + if (!gaim_presence_is_available(presence)) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(dialog->away_return), TRUE); diff -r b13013595c08 -r ced29c7b396c src/gtkprefs.c --- a/src/gtkprefs.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/gtkprefs.c Sat Sep 04 04:27:05 2004 +0000 @@ -638,7 +638,7 @@ gpointer userdata) { gint ret = 0; - gchar *name1, *name2; + gchar *name1 = NULL, *name2 = NULL; gtk_tree_model_get(model, a, 3, &name1, -1); gtk_tree_model_get(model, b, 3, &name2, -1); @@ -2284,7 +2284,9 @@ return; gtk_tree_model_get_value (GTK_TREE_MODEL(ls), &iter, 1, &val); amt = g_value_get_pointer (&val); +/* XXX CORE/UI create_away_mess(NULL, amt); +*/ } static gboolean away_message_click_cb(GtkWidget *tv, GdkEventButton *event, gpointer null) @@ -2299,7 +2301,9 @@ } void remove_away_message(GtkWidget *widget, GtkTreeView *tv) { +/* XXX CORE/UI struct away_message *am; +*/ GtkTreeIter iter; GtkTreeSelection *sel = gtk_tree_view_get_selection(tv); GtkTreeModel *model = GTK_TREE_MODEL(prefs_away_store); @@ -2389,17 +2393,24 @@ button = gtk_button_new_from_stock (GTK_STOCK_ADD); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_size_group_add_widget(sg, button); + +/* XXX CORE/UI g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(create_away_mess), NULL); +*/ button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); gtk_size_group_add_widget(sg, button); + +/* XXX CORE/UI g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(remove_away_message), event_view); +*/ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - button = gaim_pixbuf_button_from_stock(_("_Edit"), GAIM_STOCK_EDIT, GAIM_BUTTON_HORIZONTAL); + button = gaim_pixbuf_button_from_stock(_("_Edit"), GAIM_STOCK_EDIT, + GAIM_BUTTON_HORIZONTAL); gtk_size_group_add_widget(sg, button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(away_edit_sel), event_view); diff -r b13013595c08 -r ced29c7b396c src/idle.c --- a/src/idle.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/idle.c Sat Sep 04 04:27:05 2004 +0000 @@ -89,16 +89,22 @@ if (gaim_prefs_get_bool("/core/away/away_when_idle") && (idle_time > (60 * gaim_prefs_get_int("/core/away/mins_before_away"))) - && (!gc->is_auto_away)) { + && (!gc->is_auto_away)) + { + GaimPresence *presence; + + presence = gaim_account_get_presence(account); - if (!gc->away || (!*gc->away && (!gc->away_state || - !strcmp(gc->away_state, GAIM_AWAY_CUSTOM)))) { + if (gaim_presence_is_available(presence)) + { +/* XXX CORE/UI struct away_message *default_away = NULL; + GSList *l; +*/ const char *default_name; - GSList *l; default_name = gaim_prefs_get_string("/core/away/default_message"); - +/* XXX CORE/UI for(l = away_messages; l; l = l->next) { if(!strcmp(default_name, ((struct away_message *)l->data)->name)) { default_away = l->data; diff -r b13013595c08 -r ced29c7b396c src/prpl.c --- a/src/prpl.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/prpl.c Sat Sep 04 04:27:05 2004 +0000 @@ -28,6 +28,322 @@ #include "request.h" #include "util.h" +/**************************************************************************/ +/** @name Protocol Plugin API */ +/**************************************************************************/ +void +gaim_prpl_got_account_idle(GaimAccount *account, gboolean idle, + time_t idle_time) +{ + g_return_if_fail(account != NULL); + g_return_if_fail(gaim_account_is_connected(account)); + + gaim_presence_set_idle(gaim_account_get_presence(account), + idle, idle_time); +} + +void +gaim_prpl_got_account_login_time(GaimAccount *account, const char *name, + time_t login_time) +{ + GaimPresence *presence; + + g_return_if_fail(account != NULL); + g_return_if_fail(name != NULL && *name != '\0'); + g_return_if_fail(gaim_account_is_connected(account)); + + if (login_time == 0) + login_time = time(NULL); + + presence = gaim_account_get_presence(account); + + /* + * TODO: Set a presence's sign-on time. We don't support this yet. + */ + gaim_debug_warning("prpl", + "Attempting to set an account's sign-on time, but we " + "don't support this yet! FIX IT!\n"); +} + +static gboolean +set_value_from_arg(GaimStatus *status, const char *id, va_list *args) +{ + GaimValue *value; + + value = gaim_status_get_attr_value(status, id); + + if (value == NULL) + { + gaim_debug_error("prpl", + "Attempted to set an unknown attribute %s on " + "status %s\n", + id, gaim_status_get_id(status)); + return FALSE; + } + + switch (gaim_value_get_type(value)) + { + case GAIM_TYPE_CHAR: + gaim_value_set_char(value, (char)va_arg(*args, int)); + break; + + case GAIM_TYPE_UCHAR: + gaim_value_set_uchar(value, + (unsigned char)va_arg(*args, unsigned int)); + break; + + case GAIM_TYPE_BOOLEAN: + gaim_value_set_boolean(value, va_arg(*args, gboolean)); + break; + + case GAIM_TYPE_SHORT: + gaim_value_set_short(value, (short)va_arg(*args, int)); + break; + + case GAIM_TYPE_USHORT: + gaim_value_set_ushort(value, + (unsigned short)va_arg(*args, unsigned int)); + break; + + case GAIM_TYPE_INT: + gaim_value_set_int(value, va_arg(*args, int)); + break; + + case GAIM_TYPE_UINT: + gaim_value_set_uint(value, va_arg(*args, unsigned int)); + break; + + case GAIM_TYPE_LONG: + gaim_value_set_long(value, va_arg(*args, long)); + break; + + case GAIM_TYPE_ULONG: + gaim_value_set_ulong(value, va_arg(*args, unsigned long)); + break; + + case GAIM_TYPE_INT64: + gaim_value_set_int64(value, va_arg(*args, gint64)); + break; + + case GAIM_TYPE_UINT64: + gaim_value_set_uint64(value, va_arg(*args, guint64)); + break; + + case GAIM_TYPE_STRING: + gaim_value_set_string(value, va_arg(*args, char *)); + break; + + case GAIM_TYPE_OBJECT: + gaim_value_set_object(value, va_arg(*args, void *)); + break; + + case GAIM_TYPE_POINTER: + gaim_value_set_pointer(value, va_arg(*args, void *)); + break; + + case GAIM_TYPE_ENUM: + gaim_value_set_enum(value, va_arg(*args, int)); + break; + + case GAIM_TYPE_BOXED: + gaim_value_set_boxed(value, va_arg(*args, void *)); + break; + + default: + return FALSE; + } + + return TRUE; +} + +void +gaim_prpl_got_account_status(GaimAccount *account, const char *status_id, + const char *attr_id, ...) +{ + GaimPresence *presence; + GaimStatus *status; + + g_return_if_fail(account != NULL); + g_return_if_fail(status_id != NULL); + g_return_if_fail(gaim_account_is_connected(account)); + + presence = gaim_account_get_presence(account); + status = gaim_presence_get_status(presence, status_id); + + g_return_if_fail(status != NULL); + + if (attr_id != NULL) + { + va_list args; + + va_start(args, attr_id); + + while (attr_id != NULL) + { + set_value_from_arg(status, attr_id, &args); + + attr_id = va_arg(args, char *); + } + + va_end(args); + } + + gaim_presence_set_status_active(presence, status_id, TRUE); +} + +void +gaim_prpl_got_account_warning_level(GaimAccount *account, const char *username, + unsigned int level) +{ + GaimPresence *presence; + unsigned int old_level; + char buf2[1024]; + + g_return_if_fail(account != NULL); + + presence = gaim_account_get_presence(account); + + gaim_signal_emit(gaim_accounts_get_handle(), "account-warned", + account, username, level); + + old_level = gaim_presence_get_warning_level(presence); + gaim_presence_set_warning_level(presence, level); + + if (old_level >= level) + return; + + g_snprintf(buf2, sizeof(buf2), + _("%s has just been warned by %s.\n" + "Your new warning level is %d%%"), + gaim_account_get_username(account), + (username == NULL ? _("an anonymous person") : username), + level); + + gaim_notify_info(NULL, NULL, buf2, NULL); +} + +void +gaim_prpl_got_user_idle(GaimAccount *account, const char *name, + gboolean idle, time_t idle_time) +{ + GaimBuddy *buddy; + + g_return_if_fail(account != NULL); + g_return_if_fail(name != NULL); + g_return_if_fail(gaim_account_is_connected(account)); + + if ((buddy = gaim_find_buddy(account, name)) == NULL) + return; + + gaim_presence_set_idle(gaim_buddy_get_presence(buddy), idle, idle_time); +} + +void +gaim_prpl_got_user_login_time(GaimAccount *account, const char *name, + time_t login_time) +{ + GaimBuddy *buddy; + GaimPresence *presence; + + g_return_if_fail(account != NULL); + g_return_if_fail(name != NULL); + + if ((buddy = gaim_find_buddy(account, name)) == NULL) + return; + + if (login_time == 0) + login_time = time(NULL); + + presence = gaim_buddy_get_presence(buddy); + + /* + * TODO: Set a presence's sign-on time. We don't support this yet. + */ + gaim_debug_warning("prpl", + "Attempting to set a user's sign-on time, but we " + "don't support this yet! FIX IT!\n"); +} + +void +gaim_prpl_got_user_status(GaimAccount *account, const char *name, + const char *status_id, const char *attr_id, ...) +{ + GaimBuddy *buddy; + GaimPresence *presence; + GaimStatus *status; + + g_return_if_fail(account != NULL); + g_return_if_fail(name != NULL); + g_return_if_fail(status_id != NULL); + g_return_if_fail(gaim_account_is_connected(account)); + + if ((buddy = gaim_find_buddy(account, name)) == NULL) + return; + + presence = gaim_buddy_get_presence(buddy); + status = gaim_presence_get_status(presence, status_id); + + g_return_if_fail(status != NULL); + + if (attr_id != NULL) + { + va_list args; + + va_start(args, attr_id); + + while (attr_id != NULL) + { + set_value_from_arg(status, attr_id, &args); + + attr_id = va_arg(args, char *); + } + + va_end(args); + } + + gaim_presence_set_status_active(presence, status_id, TRUE); +} + +void +gaim_prpl_got_user_warning_level(GaimAccount *account, const char *name, + unsigned int level) +{ + GaimBuddy *buddy; + + g_return_if_fail(account != NULL); + g_return_if_fail(name != NULL); + + if ((buddy = gaim_find_buddy(account, name)) == NULL) + return; + + gaim_presence_set_warning_level(gaim_buddy_get_presence(buddy), level); +} + +void +gaim_prpl_set_account_status(GaimAccount *account, GaimStatus *status) +{ + GaimPlugin *prpl; + GaimPluginProtocolInfo *prpl_info; + + g_return_if_fail(account != NULL); + g_return_if_fail(status != NULL); + + prpl = gaim_find_prpl(gaim_account_get_protocol_id(account)); + + if (prpl == NULL) + return; + + prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(prpl); + + if (prpl_info->set_status != NULL) + prpl_info->set_status(account, status); +} + + +/************************************************************************** + * Protocol Plugin Subsystem API + **************************************************************************/ + GaimPlugin * gaim_find_prpl(const char *id) { diff -r b13013595c08 -r ced29c7b396c src/prpl.h --- a/src/prpl.h Sat Sep 04 03:33:16 2004 +0000 +++ b/src/prpl.h Sat Sep 04 04:27:05 2004 +0000 @@ -220,7 +220,7 @@ */ char *(*tooltip_text)(GaimBuddy *buddy); - GList *(*away_states)(GaimConnection *gc); + GList *(*status_types)(GaimConnection *gc); GList *(*blist_node_menu)(GaimBlistNode *node); GList *(*chat_info)(GaimConnection *); @@ -235,7 +235,8 @@ void (*set_info)(GaimConnection *, const char *info); int (*send_typing)(GaimConnection *, const char *name, int typing); void (*get_info)(GaimConnection *, const char *who); - void (*set_away)(GaimConnection *, const char *state, const char *message); + void (*set_status)(GaimAccount *account, GaimStatus *status); + void (*set_idle)(GaimConnection *, int idletime); void (*change_passwd)(GaimConnection *, const char *old_pass, const char *new_pass); diff -r b13013595c08 -r ced29c7b396c src/server.c --- a/src/server.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/server.c Sat Sep 04 04:27:05 2004 +0000 @@ -261,15 +261,20 @@ int serv_send_im(GaimConnection *gc, const char *name, const char *message, GaimConvImFlags imflags) { - GaimConversation *c; + GaimConversation *conv; + GaimAccount *account; + GaimPresence *presence; + GaimPluginProtocolInfo *prpl_info = NULL; int val = -EINVAL; - GaimPluginProtocolInfo *prpl_info = NULL; const gchar *auto_reply_pref; if (gc != NULL && gc->prpl != NULL) prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); - c = gaim_find_conversation_with_account(name, gc->account); + account = gaim_connection_get_account(gc); + presence = gaim_account_get_presence(account); + + conv = gaim_find_conversation_with_account(name, gc->account); if (prpl_info && prpl_info->send_im) val = prpl_info->send_im(gc, name, message, imflags); @@ -282,16 +287,17 @@ * this only reset lar->sent if we're away AND idle? */ auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); - if (gc->away && (gc->flags & GAIM_CONNECTION_AUTO_RESP) && - strcmp(auto_reply_pref, "never")) { + if ((gc->flags & GAIM_CONNECTION_AUTO_RESP) && + !gaim_presence_is_available(presence) && + strcmp(auto_reply_pref, "never")) { struct last_auto_response *lar; lar = get_last_auto_response(gc, name); lar->sent = time(NULL); } - if (c && gaim_conv_im_get_type_again_timeout(GAIM_CONV_IM(c))) - gaim_conv_im_stop_type_again_timeout(GAIM_CONV_IM(c)); + if (conv && gaim_conv_im_get_type_again_timeout(GAIM_CONV_IM(conv))) + gaim_conv_im_stop_type_again_timeout(GAIM_CONV_IM(conv)); return val; } @@ -307,63 +313,6 @@ prpl_info->get_info(gc, name); } -void serv_set_away(GaimConnection *gc, const char *state, const char *message) -{ - GaimPluginProtocolInfo *prpl_info = NULL; - GaimAccount *account; - - if (gc->away_state == NULL && state == NULL && - gc->away == NULL && message == NULL) { - - return; - } - - if ((gc->away_state != NULL && state != NULL && - !strcmp(gc->away_state, state) && - !strcmp(gc->away_state, GAIM_AWAY_CUSTOM)) && - (gc->away != NULL && message != NULL && !strcmp(gc->away, message))) { - - return; - } - - if (gc != NULL && gc->prpl != NULL) - prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); - - account = gaim_connection_get_account(gc); - - if (prpl_info && prpl_info->set_away) { - if (gc->away_state) { - g_free(gc->away_state); - gc->away_state = NULL; - } - - prpl_info->set_away(gc, state, message); - - if (gc->away && state) { - gc->away_state = g_strdup(state); - } - - gaim_signal_emit(gaim_accounts_get_handle(), "account-away", - account, state, message); - } - - /* LOG system_log(log_away, gc, NULL, OPT_LOG_BUDDY_AWAY | OPT_LOG_MY_SIGNON); */ - /* New away message... Clear out the record of sent autoresponses */ - flush_last_auto_responses(gc); -} - -void serv_set_away_all(const char *message) -{ - GList *c; - GaimConnection *g; - - for (c = gaim_connections_get_all(); c != NULL; c = c->next) { - g = (GaimConnection *)c->data; - - serv_set_away(g, GAIM_AWAY_CUSTOM, message); - } -} - void serv_set_info(GaimConnection *gc, const char *info) { GaimPluginProtocolInfo *prpl_info = NULL; @@ -447,7 +396,7 @@ { GaimPluginProtocolInfo *prpl_info = NULL; - if (buddy->idle > 0) + if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) remove_idle_buddy(buddy); if (gc != NULL && gc->prpl != NULL) @@ -472,7 +421,7 @@ GList *curb; for (curb = buddies; curb != NULL; curb = curb->next) { GaimBuddy *buddy = curb->data; - if (buddy->idle > 0) + if (gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) remove_idle_buddy(buddy); } prpl_info->remove_buddies(gc, buddies, groups); @@ -908,14 +857,18 @@ * are three or four different ways of handling it and different * things we have to do for each. */ - if (gc->away) { + if (!gaim_presence_is_available(presence)) + { time_t t = time(NULL); char *tmpmsg; GaimBuddy *b = gaim_find_buddy(gc->account, name); const char *alias = b ? gaim_buddy_get_alias(b) : name; - int row; struct last_auto_response *lar; const gchar *auto_reply_pref; + const char *away_msg; +#if 0 + int row; +#endif /* * Either we're going to queue it or not. Because of the way @@ -1001,11 +954,15 @@ * is set */ auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); + status = gaim_presence_get_active_status(presence); + away_msg = gaim_value_get_string( + gaim_status_get_attr_value(status, "message")); + if (!(gc->flags & GAIM_CONNECTION_AUTO_RESP) || - *gc->away == '\0' || - !strcmp(auto_reply_pref, "never") || - (!gc->is_idle && - !strcmp(auto_reply_pref, "awayidle"))) { + away_msg == NULL || *away_msg == '\0' || + !strcmp(auto_reply_pref, "never") || + (!gaim_presence_is_idle(presence) && + !strcmp(auto_reply_pref, "awayidle"))) { g_free(name); g_free(message); @@ -1128,7 +1085,8 @@ l_next = l->next; - if (!GAIM_BUDDY_IS_ONLINE(buddy) || buddy->idle <= 0) + if (!GAIM_BUDDY_IS_ONLINE(buddy) || + gaim_presence_is_idle(gaim_buddy_get_presence(buddy))) { remove_idle_buddy(buddy); } @@ -1171,14 +1129,14 @@ * since the epoch. */ void serv_got_update(GaimConnection *gc, const char *name, gboolean loggedin, - int evil, time_t signon, time_t idle, int type) + time_t signon) { + GaimPresence *presence; GaimAccount *account; GaimConversation *c; GaimBuddy *b; char *alias; GSList *buddies; - int old_idle; time_t current_time = time(NULL); int signing_on = 0; int signing_off = 0; @@ -1221,6 +1179,7 @@ time(NULL)); g_free(tmp); } +#if 0 else if (awayqueue && find_queue_total_by_name(b->name)) { struct queued_message *qm = g_new0(struct queued_message, 1); g_snprintf(qm->name, sizeof(qm->name), "%s", b->name); @@ -1230,6 +1189,7 @@ qm->flags = GAIM_MESSAGE_SYSTEM; message_queue = g_slist_append(message_queue, qm); } +#endif gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE); if(gaim_prefs_get_bool("/core/logging/log_system") && @@ -1244,55 +1204,15 @@ } } - if(gaim_prefs_get_bool("/core/logging/log_system") && - gaim_prefs_get_bool("/core/logging/log_away_state")) { - GaimAccount *account = gaim_connection_get_account(gc); - GaimLog *log = gaim_account_get_log(account); - char *tmp = NULL; - - if((b->uc & UC_UNAVAILABLE) && !(type & UC_UNAVAILABLE)) - tmp = g_strdup_printf(_("%s came back"), alias); - else if(!(b->uc & UC_UNAVAILABLE) && (type & UC_UNAVAILABLE)) - tmp = g_strdup_printf(_("%s went away"), alias); - - if(tmp){ - gaim_log_write(log, GAIM_MESSAGE_SYSTEM, (alias ? alias : name), - current_time, tmp); - g_free(tmp); - } - } - - if (!old_idle && idle) { - if(gaim_prefs_get_bool("/core/logging/log_system") && - gaim_prefs_get_bool("/core/logging/log_idle_state")) { - GaimAccount *account = gaim_connection_get_account(gc); - GaimLog *log = gaim_account_get_log(account); - char *tmp = g_strdup_printf(_("%s became idle"), alias); - - gaim_log_write(log, GAIM_MESSAGE_SYSTEM, (alias ? alias : name), - current_time, tmp); - g_free(tmp); - } - } else if (old_idle && !idle) { - if(gaim_prefs_get_bool("/core/logging/log_system") && - gaim_prefs_get_bool("/core/logging/log_idle_state")) { - GaimAccount *account = gaim_connection_get_account(gc); - GaimLog *log = gaim_account_get_log(account); - char *tmp = g_strdup_printf(_("%s became unidle"), alias); - - gaim_log_write(log, GAIM_MESSAGE_SYSTEM, (alias ? alias : name), - current_time, tmp); - g_free(tmp); - } - } - if (signing_off) { if (c != NULL) { char *tmp = g_strdup_printf(_("%s logged out."), alias); gaim_conversation_write(c, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); - } else if (awayqueue && find_queue_total_by_name(b->name)) { + } +#if 0 + else if (awayqueue && find_queue_total_by_name(b->name)) { struct queued_message *qm = g_new0(struct queued_message, 1); g_snprintf(qm->name, sizeof(qm->name), "%s", b->name); qm->message = g_strdup_printf(_("%s logged out."), alias); @@ -1301,6 +1221,7 @@ qm->flags = GAIM_MESSAGE_SYSTEM; message_queue = g_slist_append(message_queue, qm); } +#endif serv_got_typing_stopped(gc, name); /* obviously not typing */ gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE); @@ -1318,23 +1239,8 @@ if (gc->login_time_official && gc->login_time && signon > 0) signon += gc->login_time_official - gc->login_time; + gaim_blist_update_buddy_signon(b, signon); - gaim_blist_update_buddy_idle(b, idle); - gaim_blist_update_buddy_evil(b, evil); - gaim_blist_update_buddy_status(b, type); - - if (!old_idle && idle) - { - gaim_signal_emit(gaim_blist_get_handle(), "buddy-idle", b); - - add_idle_buddy(b); - } - else if (old_idle && !idle) - { - gaim_signal_emit(gaim_blist_get_handle(), "buddy-unidle", b); - - remove_idle_buddy(b); - } if (c != NULL) gaim_conversation_update(c, GAIM_CONV_UPDATE_AWAY); @@ -1344,40 +1250,10 @@ for (buddies = gaim_find_buddies(account, name); buddies; buddies = g_slist_remove(buddies, buddies->data)) { b = buddies->data; gaim_blist_update_buddy_presence(b, loggedin); - gaim_blist_update_buddy_idle(b, idle); - gaim_blist_update_buddy_evil(b, evil); - gaim_blist_update_buddy_status(b, type); } g_free(alias); } - -void serv_got_eviled(GaimConnection *gc, const char *name, int lev) -{ - char buf2[1024]; - GaimAccount *account; - - account = gaim_connection_get_account(gc); - - gaim_signal_emit(gaim_accounts_get_handle(), "account-warned", - account, name, lev); - - if (gc->evil >= lev) { - gc->evil = lev; - return; - } - - gc->evil = lev; - - g_snprintf(buf2, sizeof(buf2), - _("%s has just been warned by %s.\n" - "Your new warning level is %d%%"), - gaim_account_get_username(gaim_connection_get_account(gc)), - ((name == NULL) ? _("an anonymous person") : name), lev); - - gaim_notify_info(NULL, NULL, buf2, NULL); -} - void serv_got_typing(GaimConnection *gc, const char *name, int timeout, GaimTypingState state) { diff -r b13013595c08 -r ced29c7b396c src/server.h --- a/src/server.h Sat Sep 04 03:33:16 2004 +0000 +++ b/src/server.h Sat Sep 04 04:27:05 2004 +0000 @@ -25,12 +25,6 @@ #ifndef _GAIM_SERVER_H_ #define _GAIM_SERVER_H_ -/* - * Really user states are controlled by the PRPLs now. We just - * use this for event_away - */ -#define UC_UNAVAILABLE 1 - #include "account.h" #include "conversation.h" #include "prpl.h" @@ -47,8 +41,6 @@ void serv_get_dir(GaimConnection *, const char *); void serv_set_idle(GaimConnection *, int); void serv_set_info(GaimConnection *, const char *); -void serv_set_away(GaimConnection *, const char *, const char *); -void serv_set_away_all(const char *); int serv_send_typing(GaimConnection *, const char *, int); void serv_change_passwd(GaimConnection *, const char *, const char *); void serv_add_buddy(GaimConnection *, GaimBuddy *); @@ -78,7 +70,6 @@ int serv_chat_send(GaimConnection *, int, const char *); void serv_alias_buddy(GaimBuddy *); void serv_got_alias(GaimConnection *gc, const char *who, const char *alias); -void serv_got_eviled(GaimConnection *gc, const char *name, int lev); void serv_got_typing(GaimConnection *gc, const char *name, int timeout, GaimTypingState state); void serv_set_buddyicon(GaimConnection *gc, const char *filename); @@ -86,7 +77,7 @@ void serv_got_im(GaimConnection *gc, const char *who, const char *msg, GaimConvImFlags imflags, time_t mtime); void serv_got_update(GaimConnection *gc, const char *name, gboolean loggedin, - int evil, time_t signon, time_t idle, int type); + time_t signon); void serv_finish_login(GaimConnection *gc); void serv_got_chat_invite(GaimConnection *gc, const char *name, const char *who, const char *message, diff -r b13013595c08 -r ced29c7b396c src/status.c --- a/src/status.c Sat Sep 04 03:33:16 2004 +0000 +++ b/src/status.c Sat Sep 04 04:27:05 2004 +0000 @@ -22,290 +22,1480 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "internal.h" +#include "blist.h" +#include "debug.h" +#include "prefs.h" #include "status.h" -#include "internal.h" -#include "debug.h" #include "util.h" -/* XXX CORE/UI */ -#include "away.h" -#include "gtkgaim.h" +/** + * A type of status. + */ +struct _GaimStatusType +{ + GaimStatusPrimitive primitive; + char *id; + char *name; + char *primary_attr_id; + + gboolean saveable; + gboolean user_settable; + gboolean independent; + + GList *attrs; +}; -/* for people like myself who are too lazy to add an away msg :) */ -/* I don't know who "myself" is in this context. The exclamation point - * makes it slightly less boring ;) */ -#define BORING_DEFAULT_AWAY_MSG _("Sorry, I ran out for a bit!") +/** + * A status attribute. + */ +struct _GaimStatusAttr +{ + char *id; + char *name; + GaimValue *value_type; +}; -/* XML File Saving */ +/** + * A list of statuses. + */ +struct _GaimPresence +{ + GaimPresenceContext context; + + gboolean idle; + time_t idle_time; + + unsigned int warning_level; -/* All of this code is adapted from Nathan Walp's. It's adapted all over the place - * for accounts, the buddy list, pounces, preferences, and the likes. It would be - * neat if we could somehow make this more generic. */ -static gboolean status_loaded = FALSE; -static guint status_save_timer = 0; + GList *statuses; + GHashTable *status_table; + + GaimStatus *active_status; + union + { + GaimAccount *account; + + struct + { + GaimConversation *conv; + char *user; + + } chat; -typedef enum + struct + { + GaimAccount *account; + char *name; + size_t ref_count; + GList *buddies; + + } buddy; + + } u; +}; + +/** + * An active status. + */ +struct _GaimStatus { - TAG_NONE = 0, - TAG_STATUS, - TAG_STATE, - TAG_MESSAGE, + GaimStatusType *type; + GaimPresence *presence; + + const char *title; -} StatusParserTag; + gboolean active; + GHashTable *attr_values; +}; typedef struct { - StatusParserTag tag; - GString *buffer; - struct away_message *am; + GaimAccount *account; + char *name; + +} GaimStatusBuddyKey; + + +#if 0 +static GList *stored_statuses = NULL; + +/* + * XXX This stuff should be removed in a few versions. It stores the + * old v1 status stuff so we can write it later. We don't write out + * the new status stuff, though. These should all die soon, as the + * old status.xml was created before the new status system's design + * was created. + * + * -- ChipX86 + */ +typedef struct +{ + char *name; + char *state; + char *message; + +} GaimStatusV1Info; + +static GList *v1_statuses = NULL; +#endif + + +static int primitive_scores[] = +{ + 0, /* unset */ + -500, /* offline */ + 0, /* online */ + 100, /* available */ + -75, /* unavailable */ + -50, /* hidden */ + -100, /* away */ + -200 /* extended away */ + -10, /* idle, special case. */ + -5 /* idle time, special case. */ +}; + +static GHashTable *buddy_presences = NULL; + +#define SCORE_IDLE 5 +#define SCORE_IDLE_TIME 6 + +/************************************************************************** + * GaimStatusType API + **************************************************************************/ +GaimStatusType * +gaim_status_type_new_full(GaimStatusPrimitive primitive, const char *id, + const char *name, gboolean saveable, + gboolean user_settable, gboolean independent) +{ + GaimStatusType *status_type; + + g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL); + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + status_type = g_new0(GaimStatusType, 1); + + status_type->primitive = primitive; + status_type->id = g_strdup(id); + status_type->name = g_strdup(name); + status_type->saveable = saveable; + status_type->user_settable = user_settable; + status_type->independent = independent; + + return status_type; +} + +GaimStatusType * +gaim_status_type_new(GaimStatusPrimitive primitive, const char *id, + const char *name, gboolean user_settable) +{ + g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL); + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + + return gaim_status_type_new_full(primitive, id, name, FALSE, + user_settable, FALSE); +} + +GaimStatusType * +gaim_status_type_new_with_attrs(GaimStatusPrimitive primitive, + const char *id, const char *name, + gboolean saveable, gboolean user_settable, + gboolean independent, const char *attr_id, + const char *attr_name, GaimValue *attr_value, + ...) +{ + GaimStatusType *status_type; + va_list args; + + g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, NULL); + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(attr_name != NULL, NULL); + g_return_val_if_fail(attr_value != NULL, NULL); + + status_type = gaim_status_type_new_full(primitive, id, name, saveable, + user_settable, independent); + + gaim_status_type_add_attr(status_type, attr_id, attr_name, attr_value); + + va_start(args, attr_value); + gaim_status_type_add_attrs_vargs(status_type, args); + va_end(args); + + return status_type; +} + +void +gaim_status_type_destroy(GaimStatusType *status_type) +{ + GList *l; + + g_return_if_fail(status_type != NULL); + + g_free(status_type->id); + g_free(status_type->name); + + if (status_type->primary_attr_id != NULL) + g_free(status_type->primary_attr_id); + + if (status_type->attrs != NULL) + { + for (l = status_type->attrs; l != NULL; l = l->next) + gaim_status_attr_destroy((GaimStatusAttr *)l->data); + + g_list_free(status_type->attrs); + } + + g_free(status_type); +} + +void +gaim_status_type_set_primary_attr(GaimStatusType *status_type, const char *id) +{ + g_return_if_fail(status_type != NULL); + + if (status_type->primary_attr_id != NULL) + g_free(status_type->primary_attr_id); + + status_type->primary_attr_id = (id == NULL ? NULL : g_strdup(id)); +} + +void +gaim_status_type_add_attr(GaimStatusType *status_type, const char *id,\ + const char *name, GaimValue *value) +{ + GaimStatusAttr *attr; + + g_return_if_fail(status_type != NULL); + g_return_if_fail(id != NULL); + g_return_if_fail(name != NULL); + g_return_if_fail(value != NULL); + + attr = gaim_status_attr_new(id, name, value); + + status_type->attrs = g_list_append(status_type->attrs, attr); +} + +void +gaim_status_type_add_attrs(GaimStatusType *status_type, const char *id, + const char *name, GaimValue *value, ...) +{ + va_list args; + + g_return_if_fail(status_type != NULL); + g_return_if_fail(id != NULL); + g_return_if_fail(name != NULL); + g_return_if_fail(value != NULL); + + /* Add the first. */ + gaim_status_type_add_attr(status_type, id, name, value); + + va_start(args, value); + gaim_status_type_add_attrs_vargs(status_type, args); + va_end(args); +} + +void +gaim_status_type_add_attrs_vargs(GaimStatusType *status_type, va_list args) +{ + const char *id, *name; + GaimValue *value; + + g_return_if_fail(status_type != NULL); + + while ((id = va_arg(args, const char *)) != NULL) + { + name = va_arg(args, const char *); + g_return_if_fail(name != NULL); + + value = va_arg(args, GaimValue *); + g_return_if_fail(value != NULL); -} StatusParserData; + gaim_status_type_add_attr(status_type, id, name, value); + } +} + +GaimStatusPrimitive +gaim_status_type_get_primitive(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, GAIM_STATUS_UNSET); + + return status_type->primitive; +} + +const char * +gaim_status_type_get_id(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, NULL); + + return status_type->id; +} + +const char * +gaim_status_type_get_name(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, NULL); + + return status_type->name; +} + +gboolean +gaim_status_type_is_saveable(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, FALSE); + + return status_type->saveable; +} + +gboolean +gaim_status_type_is_user_settable(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, FALSE); + + return status_type->user_settable; +} + +gboolean +gaim_status_type_is_independent(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, FALSE); + + return status_type->independent; +} + +gboolean +gaim_status_type_is_available(const GaimStatusType *status_type) +{ + GaimStatusPrimitive primitive; + + g_return_val_if_fail(status_type != NULL, FALSE); + + primitive = gaim_status_type_get_primitive(status_type); + + return (primitive == GAIM_STATUS_AVAILABLE || + primitive == GAIM_STATUS_HIDDEN); +} + +const char * +gaim_status_type_get_primary_attr(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, NULL); + + return status_type->primary_attr_id; +} + +GaimStatusAttr * +gaim_status_type_get_attr(const GaimStatusType *status_type, const char *id) +{ + GList *l; + + g_return_val_if_fail(status_type != NULL, NULL); + g_return_val_if_fail(id != NULL, NULL); + + for (l = status_type->attrs; l != NULL; l = l->next) + { + GaimStatusAttr *attr = (GaimStatusAttr *)l->data; + + if (!strcmp(gaim_status_attr_get_id(attr), id)) + return attr; + } + + return NULL; +} + +const GList * +gaim_status_type_get_attrs(const GaimStatusType *status_type) +{ + g_return_val_if_fail(status_type != NULL, NULL); + + return status_type->attrs; +} + + +/************************************************************************** +* GaimStatusAttr API +**************************************************************************/ +GaimStatusAttr * +gaim_status_attr_new(const char *id, const char *name, GaimValue *value_type) +{ + GaimStatusAttr *attr; + + g_return_val_if_fail(id != NULL, NULL); + g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(value_type != NULL, NULL); + + attr = g_new0(GaimStatusAttr, 1); + + attr->id = g_strdup(id); + attr->name = g_strdup(name); + attr->value_type = value_type; + + return attr; +} + +void +gaim_status_attr_destroy(GaimStatusAttr *attr) +{ + g_return_if_fail(attr != NULL); + + g_free(attr->id); + g_free(attr->name); + + gaim_value_destroy(attr->value_type); + + g_free(attr); +} + +const char * +gaim_status_attr_get_id(const GaimStatusAttr *attr) +{ + g_return_val_if_fail(attr != NULL, NULL); + + return attr->id; +} + +const char * +gaim_status_attr_get_name(const GaimStatusAttr *attr) +{ + g_return_val_if_fail(attr != NULL, NULL); + + return attr->name; +} + +GaimValue * +gaim_status_attr_get_value_type(const GaimStatusAttr *attr) +{ + g_return_val_if_fail(attr != NULL, NULL); + + return attr->value_type; +} + + +/************************************************************************** +* GaimStatus API +**************************************************************************/ +GaimStatus * +gaim_status_new(GaimStatusType *status_type, GaimPresence *presence) +{ + GaimStatus *status; + const GList *l; + + g_return_val_if_fail(status_type != NULL, NULL); + g_return_val_if_fail(presence != NULL, NULL); + + status = g_new0(GaimStatus, 1); + + status->type = status_type; + status->presence = presence; + + status->attr_values = + g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify)gaim_value_destroy); + + for (l = gaim_status_type_get_attrs(status_type); l != NULL; l = l->next) + { + GaimStatusAttr *attr = (GaimStatusAttr *)l->data; + GaimValue *value = gaim_status_attr_get_value_type(attr); + GaimValue *new_value = gaim_value_dup(value); + + g_hash_table_insert(status->attr_values, + g_strdup(gaim_status_attr_get_id(attr)), new_value); + } + + return status; +} + +void +gaim_status_destroy(GaimStatus *status) +{ + g_return_if_fail(status != NULL); + + gaim_status_set_active(status, FALSE); + + g_hash_table_destroy(status->attr_values); + + g_free(status); +} static void -free_parser_data(gpointer user_data) +notify_buddy_status_update(GaimBuddy *buddy, GaimPresence *presence, + GaimStatus *old_status, GaimStatus *new_status) +{ + GaimBlistUiOps *ops = gaim_blist_get_ui_ops(); + + if (gaim_prefs_get_bool("/core/logging/log_system") && + gaim_prefs_get_bool("/core/logging/log_away_state")) + { + time_t current_time = time(NULL); + const char *buddy_alias = gaim_buddy_get_alias(buddy); + char *tmp = NULL; + + if (!gaim_status_is_available(old_status) && + gaim_status_is_available(new_status)) + { + tmp = g_strdup_printf(_("%s came back"), buddy_alias); + } + else if (gaim_status_is_available(old_status) && + !gaim_status_is_available(new_status)) + { + tmp = g_strdup_printf(_("%s went away"), buddy_alias); + } + + if (tmp != NULL) + { + GaimLog *log = gaim_account_get_log(buddy->account); + + gaim_log_write(log, GAIM_MESSAGE_SYSTEM, buddy_alias, + current_time, tmp); + g_free(tmp); + } + } + + if (ops != NULL && ops->status_changed != NULL) + ops->status_changed(buddy, new_status); +} + +static void +notify_status_update(GaimPresence *presence, GaimStatus *old_status, + GaimStatus *new_status) { - StatusParserData *data = user_data; + GaimPresenceContext context = gaim_presence_get_context(presence); + + if (context == GAIM_PRESENCE_CONTEXT_ACCOUNT) + { + GaimAccountUiOps *ops = gaim_accounts_get_ui_ops(); + + if (ops != NULL && ops->status_changed != NULL) + { + ops->status_changed(gaim_presence_get_account(presence), + new_status); + } + } + else if (context == GAIM_PRESENCE_CONTEXT_CONV) + { +/* TODO */ +#if 0 + GaimConversationUiOps *ops; + GaimConversation *conv; + + conv = gaim_status_get_conversation(new_status); +#endif + } + else if (context == GAIM_PRESENCE_CONTEXT_BUDDY) + { + const GList *l; + + for (l = gaim_presence_get_buddies(presence); l != NULL; l = l->next) + { + notify_buddy_status_update((GaimBuddy *)l->data, presence, + old_status, new_status); + } + } +} + +void +gaim_status_set_active(GaimStatus *status, gboolean active) +{ + GaimStatusType *status_type; + GaimPresence *presence; + GaimStatus *old_status; + + g_return_if_fail(status != NULL); + + if (status->active == active) + return; + + status_type = gaim_status_get_type(status); - if (data->buffer != NULL) - g_string_free(data->buffer, TRUE); + if (!active && gaim_status_type_is_independent(status_type)) + { + gaim_debug(GAIM_DEBUG_ERROR, "status", + "Cannot deactivate an exclusive status (%s).\n", + gaim_status_type_get_id(status_type)); + return; + } + + presence = gaim_status_get_presence(status); + old_status = gaim_presence_get_active_status(presence); + + if (!gaim_status_type_is_independent(status_type)) + { + const GList *l; + + for (l = gaim_presence_get_statuses(presence); + l != NULL; + l = l->next) + { + GaimStatus *temp_status = (GaimStatus *)l->data; + GaimStatusType *temp_type; + + if (temp_status == status) + continue; + + temp_type = gaim_status_get_type(temp_status); + + if (gaim_status_type_is_independent(temp_type)) + continue; + + if (gaim_status_is_active(temp_status)) + { + /* + * Since we don't want an infinite loop, we have to set + * the active variable ourself. + */ + temp_status->active = FALSE; + + notify_status_update(presence, old_status, temp_status); + + break; + } + } + } + + status->active = active; - g_free(data); + notify_status_update(presence, old_status, status); +} + +void +gaim_status_set_attr_boolean(GaimStatus *status, const char *id, + gboolean value) +{ + GaimStatusType *status_type; + GaimStatusAttr *attr; + GaimValue *attr_value; + + g_return_if_fail(status != NULL); + g_return_if_fail(id != NULL); + + status_type = gaim_status_get_type(status); + + /* Make sure this attribute exists. */ + attr = gaim_status_type_get_attr(status_type, id); + g_return_if_fail(attr != NULL); + + attr_value = gaim_status_attr_get_value_type(attr); + g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_BOOLEAN); + + gaim_value_set_boolean(attr_value, value); +} + +void +gaim_status_set_attr_int(GaimStatus *status, const char *id, int value) +{ + GaimStatusType *status_type; + GaimStatusAttr *attr; + GaimValue *attr_value; + + g_return_if_fail(status != NULL); + g_return_if_fail(id != NULL); + + status_type = gaim_status_get_type(status); + + /* Make sure this attribute exists. */ + attr = gaim_status_type_get_attr(status_type, id); + g_return_if_fail(attr != NULL); + + attr_value = gaim_status_attr_get_value_type(attr); + g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_INT); + + gaim_value_set_int(attr_value, value); } -static void gaim_status_write(FILE *fp, struct away_message *am) +void +gaim_status_set_attr_string(GaimStatus *status, const char *id, + const char *value) +{ + GaimStatusType *status_type; + GaimStatusAttr *attr; + GaimValue *attr_value; + + g_return_if_fail(status != NULL); + g_return_if_fail(id != NULL); + + status_type = gaim_status_get_type(status); + + /* Make sure this attribute exists. */ + attr = gaim_status_type_get_attr(status_type, id); + g_return_if_fail(attr != NULL); + + attr_value = gaim_status_attr_get_value_type(attr); + g_return_if_fail(gaim_value_get_type(attr_value) == GAIM_TYPE_STRING); + + gaim_value_set_string(attr_value, value); +} + +GaimStatusType * +gaim_status_get_type(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, NULL); + + return status->type; +} + +GaimPresence * +gaim_status_get_presence(const GaimStatus *status) { - char *esc = NULL; + g_return_val_if_fail(status != NULL, NULL); + + return status->presence; +} + +const char * +gaim_status_get_id(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, NULL); + + return gaim_status_type_get_id(gaim_status_get_type(status)); +} + +const char * +gaim_status_get_name(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, NULL); + + return gaim_status_type_get_name(gaim_status_get_type(status)); +} + +gboolean +gaim_status_is_independent(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, FALSE); + + return gaim_status_type_is_independent(gaim_status_get_type(status)); +} + +gboolean +gaim_status_is_available(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, FALSE); + + return gaim_status_type_is_available(gaim_status_get_type(status)); +} - esc = g_markup_escape_text(am->name, -1); - fprintf(fp, "\t\n", esc); - g_free(esc); +gboolean +gaim_status_is_active(const GaimStatus *status) +{ + g_return_val_if_fail(status != NULL, FALSE); + + return status->active; +} + +GaimValue * +gaim_status_get_attr_value(const GaimStatus *status, const char *id) +{ + GaimStatusType *status_type; + GaimStatusAttr *attr; + + g_return_val_if_fail(status != NULL, NULL); + g_return_val_if_fail(id != NULL, NULL); + + status_type = gaim_status_get_type(status); + + /* Make sure this attribute exists. */ + attr = gaim_status_type_get_attr(status_type, id); + g_return_val_if_fail(attr != NULL, NULL); + + return (GaimValue *)g_hash_table_lookup(status->attr_values, id); +} + +gboolean +gaim_status_get_attr_boolean(const GaimStatus *status, const char *id) +{ + const GaimValue *value; + + g_return_val_if_fail(status != NULL, FALSE); + g_return_val_if_fail(id != NULL, FALSE); + + if ((value = gaim_status_get_attr_value(status, id)) == NULL) + return FALSE; + + g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_STRING, FALSE); + + return gaim_value_get_boolean(value); +} + +int +gaim_status_get_attr_int(const GaimStatus *status, const char *id) +{ + const GaimValue *value; + + g_return_val_if_fail(status != NULL, FALSE); + g_return_val_if_fail(id != NULL, FALSE); + + if ((value = gaim_status_get_attr_value(status, id)) == NULL) + return FALSE; + + g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_INT, 0); + + return gaim_value_get_int(value); +} + +const char * +gaim_status_get_attr_string(const GaimStatus *status, const char *id) +{ + const GaimValue *value; + + g_return_val_if_fail(status != NULL, FALSE); + g_return_val_if_fail(id != NULL, FALSE); + + if ((value = gaim_status_get_attr_value(status, id)) == NULL) + return FALSE; + + g_return_val_if_fail(gaim_value_get_type(value) == GAIM_TYPE_STRING, NULL); + + return gaim_value_get_string(value); +} + +gint +gaim_status_compare(const GaimStatus *status1, const GaimStatus *status2) +{ + GaimStatusType *type1, *type2; + int score1 = 0, score2 = 0; - fprintf(fp, "\t\taway\n"); + if ((status1 == NULL && status2 == NULL) || + (status1 == status2)) + { + return 0; + } + else if (status1 == NULL) + return 1; + else if (status2 == NULL) + return -1; + + type1 = gaim_status_get_type(status1); + type2 = gaim_status_get_type(status2); + + if (gaim_status_is_active(status1)) + score1 = primitive_scores[gaim_status_type_get_primitive(type1)]; + + if (gaim_status_is_active(status2)) + score2 = primitive_scores[gaim_status_type_get_primitive(type2)]; + + if (score1 > score2) + return -1; + else if (score1 < score2) + return 1; + + return 0; +} + + +/************************************************************************** +* GaimPresence API +**************************************************************************/ +GaimPresence * +gaim_presence_new(GaimPresenceContext context) +{ + GaimPresence *presence; + + g_return_val_if_fail(context != GAIM_PRESENCE_CONTEXT_UNSET, NULL); + + presence = g_new0(GaimPresence, 1); + + presence->context = context; + + presence->status_table = + g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, (GFreeFunc)gaim_status_destroy); + + return presence; +} + +GaimPresence * +gaim_presence_new_for_account(GaimAccount *account) +{ + GaimPresence *presence; + + g_return_val_if_fail(account != NULL, NULL); + + presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_ACCOUNT); + + presence->u.account = account; + + return presence; +} + +GaimPresence * +gaim_presence_new_for_conv(GaimConversation *conv) +{ + GaimPresence *presence; + + g_return_val_if_fail(conv != NULL, NULL); + + presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_CONV); + + presence->u.chat.conv = conv; + + return presence; +} - esc = g_markup_escape_text(am->message, -1); - fprintf(fp, "\t\t%s\n", esc); - g_free(esc); +GaimPresence * +gaim_presence_new_for_buddy(GaimBuddy *buddy) +{ + GaimPresence *presence; + GaimStatusBuddyKey *key; + + g_return_val_if_fail(buddy != NULL, NULL); + + key = g_new0(GaimStatusBuddyKey, 1); + key->account = buddy->account; + key->name = g_strdup(buddy->name); + + if ((presence = g_hash_table_lookup(buddy_presences, key)) == NULL) + { + presence = gaim_presence_new(GAIM_PRESENCE_CONTEXT_BUDDY); + + presence->u.buddy.name = g_strdup(buddy->name); + presence->u.buddy.account = buddy->account; + + g_hash_table_insert(buddy_presences, key, presence); + } + else + { + g_free(key->name); + g_free(key); + } + + presence->u.buddy.ref_count++; + presence->u.buddy.buddies = g_list_append(presence->u.buddy.buddies, + buddy); + + return presence; +} + +void +gaim_presence_destroy(GaimPresence *presence) +{ + g_return_if_fail(presence != NULL); - fprintf(fp, "\t\n"); + if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY) + { + GaimStatusBuddyKey key; + + presence->u.buddy.ref_count--; + + g_return_if_fail(presence->u.buddy.ref_count == 0); + + key.account = presence->u.buddy.account; + key.name = presence->u.buddy.name; + + g_hash_table_remove(buddy_presences, &key); + + if (presence->u.buddy.name != NULL) + g_free(presence->u.buddy.name); + } + else if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_CONV) + { + if (presence->u.chat.user != NULL) + g_free(presence->u.chat.user); + } + + if (presence->statuses != NULL) + g_list_free(presence->statuses); + + g_hash_table_destroy(presence->status_table); + + g_free(presence); +} + +void +gaim_presence_remove_buddy(GaimPresence *presence, GaimBuddy *buddy) +{ + g_return_if_fail(presence != NULL); + g_return_if_fail(buddy != NULL); + g_return_if_fail(gaim_presence_get_context(presence) == + GAIM_PRESENCE_CONTEXT_BUDDY); + + if (g_list_find(presence->u.buddy.buddies, buddy) != NULL) + { + presence->u.buddy.buddies = g_list_remove(presence->u.buddy.buddies, + buddy); + presence->u.buddy.ref_count--; + } } -static gboolean -status_save_cb(gpointer unused) +void +gaim_presence_add_status(GaimPresence *presence, GaimStatus *status) +{ + g_return_if_fail(presence != NULL); + g_return_if_fail(status != NULL); + + presence->statuses = g_list_append(presence->statuses, status); + + g_hash_table_insert(presence->status_table, + g_strdup(gaim_status_get_id(status)), status); +} + +void +gaim_presence_add_presence(GaimPresence *presence, const GList *source_list) +{ + const GList *l; + + g_return_if_fail(presence != NULL); + g_return_if_fail(source_list != NULL); + + for (l = source_list; l != NULL; l = l->next) + gaim_presence_add_status(presence, (GaimStatus *)l->data); +} + +void +gaim_presence_set_status_active(GaimPresence *presence, const char *status_id, + gboolean active) +{ + GaimStatus *status; + + g_return_if_fail(presence != NULL); + g_return_if_fail(status_id != NULL); + + status = gaim_presence_get_status(presence, status_id); + + g_return_if_fail(status != NULL); + + if (!gaim_status_is_independent(status)) + { + if (!active) + { + gaim_debug_warning("status", + "Attempted to set a non-independent status " + "(%s) inactive. Only independent statuses " + "can be specifically marked inactive.", + status_id); + + return; + } + + if (presence->active_status != NULL) + gaim_status_set_active(presence->active_status, FALSE); + + presence->active_status = status; + } + + gaim_status_set_active(status, active); +} + +void +gaim_presence_switch_status(GaimPresence *presence, const char *status_id) +{ + GaimStatus *status; + + g_return_if_fail(presence != NULL); + g_return_if_fail(status_id != NULL); + + status = gaim_presence_get_status(presence, status_id); + + g_return_if_fail(status != NULL); + + if (gaim_status_is_independent(status)) + return; + + if (presence->active_status != NULL) + gaim_status_set_active(presence->active_status, FALSE); + + gaim_status_set_active(status, TRUE); +} + +static void +update_buddy_idle(GaimBuddy *buddy, GaimPresence *presence, + time_t current_time, gboolean old_idle, gboolean idle) +{ + GaimBlistUiOps *ops = gaim_get_blist()->ui_ops; + + if (!old_idle && idle) + { + gaim_signal_emit(gaim_blist_get_handle(), "buddy-idle", buddy); + + if (gaim_prefs_get_bool("/core/logging/log_system") && + gaim_prefs_get_bool("/core/logging/log_idle_state")) + { + GaimLog *log = gaim_account_get_log(buddy->account); + char *tmp = g_strdup_printf(_("%s became idle"), + gaim_buddy_get_alias(buddy)); + + gaim_log_write(log, GAIM_MESSAGE_SYSTEM, + gaim_buddy_get_alias(buddy), current_time, tmp); + g_free(tmp); + } + } + else if (old_idle && !idle) + { + gaim_signal_emit(gaim_blist_get_handle(), "buddy-unidle", buddy); + + if (gaim_prefs_get_bool("/core/logging/log_system") && + gaim_prefs_get_bool("/core/logging/log_idle_state")) + { + GaimLog *log = gaim_account_get_log(buddy->account); + char *tmp = g_strdup_printf(_("%s became unidle"), + gaim_buddy_get_alias(buddy)); + + gaim_log_write(log, GAIM_MESSAGE_SYSTEM, + gaim_buddy_get_alias(buddy), current_time, tmp); + g_free(tmp); + } + } + + gaim_contact_compute_priority_buddy(gaim_buddy_get_contact(buddy)); + + if (ops != NULL && ops->update != NULL) + ops->update(gaim_get_blist(), (GaimBlistNode *)buddy); +} + +void +gaim_presence_set_idle(GaimPresence *presence, gboolean idle, time_t idle_time) +{ + gboolean old_idle; + + g_return_if_fail(presence != NULL); + + if (presence->idle == idle && presence->idle_time == idle_time) + return; + + old_idle = presence->idle; + presence->idle = idle; + presence->idle_time = (idle ? idle_time : 0); + + if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY) + { + const GList *l; + time_t current_time = time(NULL); + + for (l = gaim_presence_get_buddies(presence); l != NULL; l = l->next) + { + update_buddy_idle((GaimBuddy *)l->data, presence, current_time, + old_idle, idle); + } + } +} + +void +gaim_presence_set_warning_level(GaimPresence *presence, unsigned int level) { - gaim_status_sync(); - status_save_timer = 0; + g_return_if_fail(presence != NULL); + g_return_if_fail(level <= 100); + + if (presence->warning_level == level) + return; + + presence->warning_level = level; + + if (gaim_presence_get_context(presence) == GAIM_PRESENCE_CONTEXT_BUDDY) + { + GaimBlistUiOps *ops = gaim_get_blist()->ui_ops; + + if (ops != NULL && ops->update != NULL) + { + const GList *l; + + for (l = gaim_presence_get_buddies(presence); + l != NULL; + l = l->next) + { + ops->update(gaim_get_blist(), (GaimBlistNode *)l->data); + } + } + } +} + +GaimPresenceContext +gaim_presence_get_context(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, GAIM_PRESENCE_CONTEXT_UNSET); + + return presence->context; +} + +GaimAccount * +gaim_presence_get_account(const GaimPresence *presence) +{ + GaimPresenceContext context; + + g_return_val_if_fail(presence != NULL, NULL); + + context = gaim_presence_get_context(presence); + + g_return_val_if_fail(context == GAIM_PRESENCE_CONTEXT_ACCOUNT || + context == GAIM_PRESENCE_CONTEXT_BUDDY, NULL); + + return presence->u.account; +} + +GaimConversation * +gaim_presence_get_conversation(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, NULL); + g_return_val_if_fail(gaim_presence_get_context(presence) == + GAIM_PRESENCE_CONTEXT_CONV, NULL); + + return presence->u.chat.conv; +} + +const char * +gaim_presence_get_chat_user(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, NULL); + g_return_val_if_fail(gaim_presence_get_context(presence) == + GAIM_PRESENCE_CONTEXT_CONV, NULL); + + return presence->u.chat.user; +} + +const GList * +gaim_presence_get_buddies(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, NULL); + g_return_val_if_fail(gaim_presence_get_context(presence) == + GAIM_PRESENCE_CONTEXT_BUDDY, NULL); + + return presence->u.buddy.buddies; +} + +const GList * +gaim_presence_get_statuses(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, NULL); + + return presence->statuses; +} + +GaimStatus * +gaim_presence_get_status(const GaimPresence *presence, const char *status_id) +{ + GaimStatus *status; + + g_return_val_if_fail(presence != NULL, NULL); + g_return_val_if_fail(status_id != NULL, NULL); + + status = (GaimStatus *)g_hash_table_lookup(presence->status_table, + status_id); + + return status; +} + +GaimStatus * +gaim_presence_get_active_status(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, NULL); + + return presence->active_status; +} + +gboolean +gaim_presence_is_available(const GaimPresence *presence) +{ + GaimStatus *status; + + g_return_val_if_fail(presence != NULL, FALSE); + + status = gaim_presence_get_active_status(presence); + + return ((status != NULL && gaim_status_is_available(status)) && + !gaim_presence_is_idle(presence)); +} + +gboolean +gaim_presence_is_online(const GaimPresence *presence) +{ + GaimStatus *status; + GaimStatusPrimitive primitive; + + g_return_val_if_fail(presence != NULL, FALSE); + + if ((status = gaim_presence_get_active_status(presence)) == NULL) + return FALSE; + + primitive = gaim_status_type_get_primitive(gaim_status_get_type(status)); + + return (primitive != GAIM_STATUS_UNSET && + primitive != GAIM_STATUS_OFFLINE); +} + +gboolean +gaim_presence_is_status_active(const GaimPresence *presence, + const char *status_id) +{ + GaimStatus *status; + + g_return_val_if_fail(presence != NULL, FALSE); + g_return_val_if_fail(status_id != NULL, FALSE); + + status = gaim_presence_get_status(presence, status_id); + + return (status != NULL && gaim_status_is_active(status)); +} + +gboolean +gaim_presence_is_status_primitive_active(const GaimPresence *presence, + GaimStatusPrimitive primitive) +{ + GaimStatus *status; + GaimStatusType *status_type; + + g_return_val_if_fail(presence != NULL, FALSE); + g_return_val_if_fail(primitive != GAIM_STATUS_UNSET, FALSE); + + status = gaim_presence_get_active_status(presence); + status_type = gaim_status_get_type(status); + + if (gaim_status_type_get_primitive(status_type) == primitive) + return TRUE; return FALSE; } -static void -schedule_status_save() +gboolean +gaim_presence_is_idle(const GaimPresence *presence) { - if (!status_save_timer) - status_save_timer = gaim_timeout_add(5000, status_save_cb, NULL); + g_return_val_if_fail(presence != NULL, FALSE); + + return presence->idle; } -static void -start_element_handler(GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, GError **error) +time_t +gaim_presence_get_idle_time(const GaimPresence *presence) { - const char *value; - StatusParserData *data = user_data; - GHashTable *atts; - int i; - - atts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - - for (i = 0; attribute_names[i] != NULL; i++) { - g_hash_table_insert(atts, g_strdup(attribute_names[i]), - g_strdup(attribute_values[i])); - } + g_return_val_if_fail(presence != NULL, 0); - if (data->buffer != NULL) { - g_string_free(data->buffer, TRUE); - data->buffer = NULL; - } + return presence->idle_time; +} - if (!strcmp(element_name, "status")) { - data->tag = TAG_STATUS; - if ((value = g_hash_table_lookup(atts, "name")) != NULL) { - data->am = g_new0(struct away_message, 1); - g_snprintf(data->am->name, sizeof(data->am->name), "%s", value); - away_messages = g_slist_append(away_messages, data->am); - } - } else if (!strcmp(element_name, "message")) { - data->tag = TAG_MESSAGE; +unsigned int +gaim_presence_get_warning_level(const GaimPresence *presence) +{ + g_return_val_if_fail(presence != NULL, 0); - } - - g_hash_table_destroy(atts); + return presence->warning_level; } -static void -end_element_handler(GMarkupParseContext *context, const gchar *element_name, - gpointer user_data, GError **error) +gint +gaim_presence_compare(const GaimPresence *presence1, + const GaimPresence *presence2) { - StatusParserData *data = user_data; - gchar *buffer; + gboolean idle1, idle2; + size_t idle_time_1, idle_time_2; + int score1 = 0, score2 = 0; + const GList *l; - if (data->buffer == NULL) - return; + if ((presence1 == NULL && presence2 == NULL) || (presence1 == presence2)) + return 0; + else if (presence1 == NULL) + return -1; + else if (presence2 == NULL) + return 1; - buffer = g_string_free(data->buffer, FALSE); - data->buffer = NULL; + /* Compute the score of the first set of statuses. */ + for (l = gaim_presence_get_statuses(presence1); l != NULL; l = l->next) + { + GaimStatus *status = (GaimStatus *)l->data; + GaimStatusType *type = gaim_status_get_type(status); - if (data->tag == TAG_MESSAGE) { - if (*buffer != '\0') - g_snprintf(data->am->message, sizeof(data->am->message), "%s", buffer); + if (gaim_status_is_active(status)) + score1 += primitive_scores[gaim_status_type_get_primitive(type)]; } - data->tag = TAG_NONE; - - g_free(buffer); -} - -static void -text_handler(GMarkupParseContext *context, const gchar *text, - gsize text_len, gpointer user_data, GError **error) -{ - StatusParserData *data = user_data; - - if (data->buffer == NULL) - data->buffer = g_string_new_len(text, text_len); - else - g_string_append_len(data->buffer, text, text_len); -} + /* Compute the score of the second set of statuses. */ + for (l = gaim_presence_get_statuses(presence1); l != NULL; l = l->next) + { + GaimStatus *status = (GaimStatus *)l->data; + GaimStatusType *type = gaim_status_get_type(status); -static GMarkupParser status_parser = -{ - start_element_handler, - end_element_handler, - text_handler, - NULL, - NULL -}; - -void gaim_status_sync() -{ - FILE *fp; - const char *user_dir = gaim_user_dir(); - char *filename, *filename_real; - - if (!status_loaded) { - gaim_debug(GAIM_DEBUG_WARNING, "status", "Writing status to disk.\n"); - schedule_status_save(); - return; + if (gaim_status_is_active(status)) + score2 += primitive_scores[gaim_status_type_get_primitive(type)]; } - if (user_dir == NULL) - return; + idle1 = gaim_presence_is_idle(presence1); + idle2 = gaim_presence_is_idle(presence2); - gaim_debug(GAIM_DEBUG_INFO, "status", "Saving statuses to disk\n"); - - fp = fopen(user_dir, "r"); + if (idle1) + score1 += primitive_scores[SCORE_IDLE]; - if (fp == NULL) - mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); - else - fclose(fp); - - filename = g_build_filename(user_dir, "status.xml.save", NULL); + if (idle2) + score2 += primitive_scores[SCORE_IDLE]; - if ((fp = fopen(filename, "w")) != NULL) { - GSList *l; + idle_time_1 = gaim_presence_get_idle_time(presence1); + idle_time_2 = gaim_presence_get_idle_time(presence2); - fprintf(fp, "\n\n"); - fprintf(fp, "\n"); - - for (l = away_messages; l != NULL; l = l->next) - gaim_status_write(fp, l->data); + if (idle_time_1 > idle_time_2) + score1 += primitive_scores[SCORE_IDLE_TIME]; + else if (idle_time_1 < idle_time_2) + score2 += primitive_scores[SCORE_IDLE_TIME]; - fprintf(fp, "\n"); + if (score1 < score2) + return 1; + else if (score1 > score2) + return -1; + + return 0; +} + - fclose(fp); - chmod(filename, S_IRUSR | S_IWUSR); - } - else { - gaim_debug(GAIM_DEBUG_ERROR, "status", "Unable to write %s\n", - filename); - g_free(filename); - return; - } +/************************************************************************** +* Status subsystem +**************************************************************************/ +static void +score_pref_changed_cb(const char *name, GaimPrefType type, gpointer value, + gpointer data) +{ + int index = GPOINTER_TO_INT(data); - filename_real = g_build_filename(user_dir, "status.xml", NULL); - - if (rename(filename, filename_real) < 0) { - gaim_debug(GAIM_DEBUG_ERROR, "status", "Error renaming %s to %s\n", - filename, filename_real); - } - - g_free(filename); - g_free(filename_real); - + primitive_scores[index] = GPOINTER_TO_INT(value); } -void gaim_status_load() +void +gaim_statuses_init(void) { - gchar *filename = g_build_filename(gaim_user_dir(), "status.xml", NULL); - gchar *contents = NULL; - gsize length; - GMarkupParseContext *context; - GError *error = NULL; - StatusParserData *parser_data; - - if (filename == NULL) { - status_loaded = TRUE; - return; - } + gaim_prefs_add_none("/core/status"); + gaim_prefs_add_none("/core/status/scores"); - if (!g_file_get_contents(filename, &contents, &length, &error)) { - gaim_debug(GAIM_DEBUG_ERROR, "status", - "Error reading statuses: %s\n", error->message); - g_error_free(error); - g_free(filename); - status_loaded = TRUE; - if (!away_messages) { - struct away_message *a = g_new0(struct away_message, 1); - g_snprintf(a->name, sizeof(a->name), _("Slightly less boring default")); - g_snprintf(a->message, sizeof(a->message), "%s", _(BORING_DEFAULT_AWAY_MSG)); - away_messages = g_slist_append(away_messages, a); - } - return; - } + gaim_prefs_add_int("/core/status/scores/offline", + primitive_scores[GAIM_STATUS_OFFLINE]); + gaim_prefs_add_int("/core/status/scores/available", + primitive_scores[GAIM_STATUS_AVAILABLE]); + gaim_prefs_add_int("/core/status/scores/hidden", + primitive_scores[GAIM_STATUS_HIDDEN]); + gaim_prefs_add_int("/core/status/scores/away", + primitive_scores[GAIM_STATUS_AWAY]); + gaim_prefs_add_int("/core/status/scores/extended_away", + primitive_scores[GAIM_STATUS_EXTENDED_AWAY]); + gaim_prefs_add_int("/core/status/scores/idle", + primitive_scores[SCORE_IDLE]); - parser_data = g_new0(StatusParserData, 1); - - context = g_markup_parse_context_new(&status_parser, 0, - parser_data, free_parser_data); - - if (!g_markup_parse_context_parse(context, contents, length, NULL)) { - g_markup_parse_context_free(context); - g_free(contents); - g_free(filename); - status_loaded = TRUE; - return; - } + gaim_prefs_connect_callback("/core/status/scores/offline", + score_pref_changed_cb, + GINT_TO_POINTER(GAIM_STATUS_OFFLINE)); + gaim_prefs_connect_callback("/core/status/scores/available", + score_pref_changed_cb, + GINT_TO_POINTER(GAIM_STATUS_AVAILABLE)); + gaim_prefs_connect_callback("/core/status/scores/hidden", + score_pref_changed_cb, + GINT_TO_POINTER(GAIM_STATUS_HIDDEN)); + gaim_prefs_connect_callback("/core/status/scores/away", + score_pref_changed_cb, + GINT_TO_POINTER(GAIM_STATUS_AWAY)); + gaim_prefs_connect_callback("/core/status/scores/extended_away", + score_pref_changed_cb, + GINT_TO_POINTER(GAIM_STATUS_EXTENDED_AWAY)); + gaim_prefs_connect_callback("/core/status/scores/idle", + score_pref_changed_cb, + GINT_TO_POINTER(SCORE_IDLE)); +} - if (!g_markup_parse_context_end_parse(context, NULL)) { - gaim_debug(GAIM_DEBUG_ERROR, "status", "Error parsing %s\n", - filename); - g_markup_parse_context_free(context); - g_free(contents); - g_free(filename); - status_loaded = TRUE; - return; - } +void +gaim_statuses_uninit(void) +{ +} - g_markup_parse_context_free(context); - g_free(contents); - g_free(filename); - status_loaded = TRUE; - return; +void +gaim_statuses_sync(void) +{ } + +void +gaim_statuses_load(void) +{ +}