# HG changeset patch # User Mikael Berthe # Date 1203967676 -3600 # Node ID 071c8170b7de1ea782eaa99b10c040544cc1ed6a # Parent 6fb141142388c30f3234171fb77b2463daf484ad Add option 'statefile' to keep track of unread messages across restarts (Suggested by micressor) diff -r 6fb141142388 -r 071c8170b7de mcabber/mcabberrc.example --- a/mcabber/mcabberrc.example Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/mcabberrc.example Mon Feb 25 20:27:56 2008 +0100 @@ -146,7 +146,12 @@ # Default = 0 (disabled -- everything is loaded) # Note: this option is only used when reading history files, not later. #set max_history_age = 0 -# + +# mcabber can store the list of unread messages in a state file, +# so that the message flags are set back at next startup. +# Note that 'logging' must be enabled for this feature to work. +#set statefile = ~/.mcabber/mcabber.state + # You can specify a maximum number of data blocks per buffer (1 block contains # about 8kB). The default is 0 (unlimited). If set, this value must be > 2. #set max_history_blocks = 8 diff -r 6fb141142388 -r 071c8170b7de mcabber/src/histolog.c --- a/mcabber/src/histolog.c Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/src/histolog.c Mon Feb 25 20:27:56 2008 +0100 @@ -26,14 +26,16 @@ #include #include #include +#include #include "histolog.h" #include "hbuf.h" #include "jabglue.h" #include "utils.h" -#include "logprint.h" +#include "screen.h" #include "settings.h" #include "utils.h" +#include "roster.h" static guint UseFileLogging; static guint FileLoadLogs; @@ -391,6 +393,11 @@ } } +guint hlog_is_enabled(void) +{ + return UseFileLogging; +} + inline void hlog_write_message(const char *bjid, time_t timestamp, int sent, const char *msg) { @@ -416,4 +423,115 @@ status_msg); } + +// hlog_save_state() +// If enabled, save the current state of the roster +// (i.e. pending messages) to a temporary file. +void hlog_save_state(void) +{ + gpointer unread_ptr, first_unread; + const char *bjid; + char *statefile_xp; + FILE *fp; + const char *statefile = settings_opt_get("statefile"); + + if (!statefile || !UseFileLogging) + return; + + statefile_xp = expand_filename(statefile); + fp = fopen(statefile_xp, "w"); + if (!fp) { + scr_LogPrint(LPRINT_NORMAL, "Cannot open state file [%s]", + strerror(errno)); + goto hlog_save_state_return; + } + + if (!jb_getonline()) { + // We're not connected. Let's use the unread_jids hash. + GList *unread_jid = unread_jid_get_list(); + unread_ptr = unread_jid; + for ( ; unread_jid ; unread_jid = g_list_next(unread_jid)) + fprintf(fp, "%s\n", (char*)unread_jid->data); + g_list_free(unread_ptr); + goto hlog_save_state_return; + } + + if (!current_buddy) // Safety check -- shouldn't happen. + goto hlog_save_state_return; + + // We're connected. Let's use unread_msg(). + unread_ptr = first_unread = unread_msg(NULL); + if (!first_unread) + goto hlog_save_state_return; + + do { + guint type = buddy_gettype(unread_ptr); + if (type & (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)) { + bjid = buddy_getjid(unread_ptr); + if (bjid) + fprintf(fp, "%s\n", bjid); + } + unread_ptr = unread_msg(unread_ptr); + } while (unread_ptr && unread_ptr != first_unread); + +hlog_save_state_return: + if (fp) { + long filelen = ftell(fp); + fclose(fp); + if (!filelen) + unlink(statefile_xp); + } + g_free(statefile_xp); +} + +// hlog_load_state() +// If enabled, load the current state of the roster +// (i.e. pending messages) from a temporary file. +// This function adds the JIDs to the unread_jids hash table, +// so it should only be called at startup. +void hlog_load_state(void) +{ + char bjid[1024]; + char *statefile_xp; + FILE *fp; + const char *statefile = settings_opt_get("statefile"); + + if (!statefile || !UseFileLogging) + return; + + statefile_xp = expand_filename(statefile); + fp = fopen(statefile_xp, "r"); + if (fp) { + char *eol; + while (!feof(fp)) { + if (fgets(bjid, sizeof bjid, fp) == NULL) + break; + // Let's remove the trailing newline. + // Also remove whitespace, if the file as been (badly) manually modified. + for (eol = bjid; *eol; eol++) ; + for (eol--; eol >= bjid && (*eol == '\n' || *eol == ' '); *eol-- = 0) ; + // Safety checks... + if (!bjid[0]) + continue; + if (check_jid_syntax(bjid)) { + scr_LogPrint(LPRINT_LOGNORM, + "ERROR: Invalid JID in state file. Corrupted file?"); + break; + } + // Display a warning if there are pending messages but the user + // won't see them because load_log isn't set. + if (!FileLoadLogs) { + scr_LogPrint(LPRINT_LOGNORM, "WARNING: unread message from <%s>.", + bjid); + scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID, TRUE); + } + // Add the JID to unread_jids. It will be used when the contact is + // added to the roster. + unread_jid_add(bjid); + } + fclose(fp); + } + g_free(statefile_xp); +} + /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ diff -r 6fb141142388 -r 071c8170b7de mcabber/src/histolog.h --- a/mcabber/src/histolog.h Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/src/histolog.h Mon Feb 25 20:27:56 2008 +0100 @@ -12,6 +12,8 @@ const char *msg); void hlog_write_status(const char *bjid, time_t timestamp, enum imstatus status, const char *status_msg); +void hlog_save_state(void); +void hlog_load_state(void); #endif /* __HISTOLOG_H__ */ diff -r 6fb141142388 -r 071c8170b7de mcabber/src/main.c --- a/mcabber/src/main.c Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/src/main.c Mon Feb 25 20:27:56 2008 +0100 @@ -499,6 +499,9 @@ fifo_init(settings_opt_get("fifo_name")); #endif + /* Load previous roster state */ + hlog_load_state(); + if (ret < 0) { scr_LogPrint(LPRINT_NORMAL, "No configuration file has been found."); scr_ShowBuddyWindow(); @@ -539,10 +542,11 @@ #endif #ifdef HAVE_ASPELL_H /* Deinitialize aspell */ - if (settings_opt_get_int("aspell_enable")) { + if (settings_opt_get_int("aspell_enable")) spellcheck_deinit(); - } #endif + /* Save pending message state */ + hlog_save_state(); printf("\n\nThanks for using mcabber!\n"); diff -r 6fb141142388 -r 071c8170b7de mcabber/src/roster.c --- a/mcabber/src/roster.c Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/src/roster.c Mon Feb 25 20:27:56 2008 +0100 @@ -24,6 +24,7 @@ #include "roster.h" #include "utils.h" +extern void hlog_save_state(void); char *strrole[] = { /* Should match enum in roster.h */ "none", @@ -118,8 +119,7 @@ static roster roster_special; -void unread_jid_add(const char *jid); -int unread_jid_del(const char *jid); +static int unread_jid_del(const char *jid); #define DFILTER_ALL 63 #define DFILTER_ONLINE 62 @@ -590,6 +590,7 @@ GSList *sl_user; roster *roster_usr, *roster_grp; int new_roster_item = FALSE; + guint unread_list_modified = FALSE; if (special) { //sl_user = roster_find(jid, namesearch, ROSTER_TYPE_SPECIAL); @@ -622,6 +623,8 @@ roster_usr = (roster*)sl_user->data; roster_grp = (roster*)roster_usr->list->data; if (value) { + if (!(roster_usr->flags & ROSTER_FLAG_MSG)) + unread_list_modified = TRUE; // Message flag is TRUE. This is easy, we just have to set both flags // to TRUE... roster_usr->flags |= ROSTER_FLAG_MSG; @@ -632,6 +635,8 @@ } else { // Message flag is FALSE. guint msg = FALSE; + if (roster_usr->flags & ROSTER_FLAG_MSG) + unread_list_modified = TRUE; roster_usr->flags &= ~ROSTER_FLAG_MSG; if (unread_list) { GSList *node = g_slist_find(unread_list, roster_usr); @@ -660,6 +665,9 @@ if (buddylist && (new_roster_item || !g_list_find(buddylist, roster_usr))) buddylist_build(); + + if (unread_list_modified) + hlog_save_state(); } const char *roster_getname(const char *jid) @@ -1541,11 +1549,22 @@ // unread_jid_del(jid) // Return TRUE if jid is found in the table (and remove it), FALSE if not -int unread_jid_del(const char *jid) +static int unread_jid_del(const char *jid) { if (!unread_jids) return FALSE; return g_hash_table_remove(unread_jids, jid); } +// unread_jid_get_list() +// Return the JID list. +// The content of the list should not be modified or freed. +// The caller should call g_list_free() after use. +GList *unread_jid_get_list(void) +{ + if (!unread_jids) + return NULL; + return g_hash_table_get_keys(unread_jids); +} + /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ diff -r 6fb141142388 -r 071c8170b7de mcabber/src/roster.h --- a/mcabber/src/roster.h Sun Feb 24 17:46:13 2008 +0100 +++ b/mcabber/src/roster.h Mon Feb 25 20:27:56 2008 +0100 @@ -232,6 +232,9 @@ void *param); gpointer unread_msg(gpointer rosterdata); +void unread_jid_add(const char *jid); +GList *unread_jid_get_list(void); + GSList *compl_list(guint type); #endif /* __ROSTER_H__ */