From: <ro...@us...> - 2006-08-09 04:21:45
|
Revision: 16675 Author: roast Date: 2006-08-08 21:21:36 -0700 (Tue, 08 Aug 2006) ViewCVS: http://svn.sourceforge.net/gaim/?rev=16675&view=rev Log Message: ----------- working event and status (aka action) logging framework try Modified Paths: -------------- branches/soc-2006-file-loggers/src/log.c branches/soc-2006-file-loggers/src/log.h Modified: branches/soc-2006-file-loggers/src/log.c =================================================================== --- branches/soc-2006-file-loggers/src/log.c 2006-08-09 03:41:45 UTC (rev 16674) +++ branches/soc-2006-file-loggers/src/log.c 2006-08-09 04:21:36 UTC (rev 16675) @@ -48,8 +48,11 @@ static void log_get_log_sets_common(GHashTable *sets); -static gsize xml_logger_write(GaimLog *log, GaimMessageFlags type, - const char *from, time_t time, const char *message); +static gsize xml_logger_write_message(GaimLog *log, GaimMessageFlags type, + const char *from, time_t time, const char *message); +static gsize xml_logger_write_action(GaimLog *log, GaimActionType action, + const char *from, time_t time, const char *data); +static gboolean xml_logger_append_footer(GIOChannel *channel); static void xml_logger_finalize(GaimLog *log); static GList *xml_logger_list(GaimLogType type, const char *sn, GaimAccount *account); static GList *xml_logger_list_syslog(GaimAccount *account); @@ -79,6 +82,70 @@ static char *txt_logger_read(GaimLog *log, GaimLogReadFlags *flags); static int txt_logger_total_size(GaimLogType type, const char *name, GaimAccount *account); +static GaimActionData supported_actions[] = { + { GAIM_ACTION_UNSET_ACTION, GAIM_ACTION_UNSET_ACTION, FALSE, NULL}, + { GAIM_ACTION_UNSET_STATUS, GAIM_ACTION_UNSET_STATUS, FALSE, NULL}, + { GAIM_ACTION_STATUS_ONLINE, GAIM_ACTION_UNSET_ACTION, TRUE, "online"}, + { GAIM_ACTION_STATUS_FREETOCHAT, GAIM_ACTION_STATUS_ONLINE, TRUE, "freeToChat"}, + { GAIM_ACTION_STATUS_MOBILE, GAIM_ACTION_STATUS_ONLINE, TRUE, "mobile"}, + { GAIM_ACTION_STATUS_OFFLINE, GAIM_ACTION_UNSET_ACTION, TRUE, "offline"}, + { GAIM_ACTION_STATUS_INVISIBLE, GAIM_ACTION_STATUS_OFFLINE, TRUE, "invisible"}, + { GAIM_ACTION_STATUS_AWAY, GAIM_ACTION_UNSET_ACTION, TRUE, "away"}, + { GAIM_ACTION_STATUS_BERIGHTBACK, GAIM_ACTION_STATUS_AWAY, TRUE, "beRightBack"}, + { GAIM_ACTION_STATUS_BUSY, GAIM_ACTION_STATUS_AWAY, TRUE, "busy"}, + { GAIM_ACTION_STATUS_DONOTDISTURB, GAIM_ACTION_STATUS_AWAY, TRUE, "doNotDisturb"}, + { GAIM_ACTION_STATUS_EXTENDEDAWAY, GAIM_ACTION_STATUS_AWAY, TRUE, "extendedAway"}, + { GAIM_ACTION_STATUS_GONEHOME, GAIM_ACTION_STATUS_AWAY, TRUE, "goneHome"}, + { GAIM_ACTION_STATUS_INAMEETING, GAIM_ACTION_STATUS_AWAY, TRUE, "inAMeeting"}, + { GAIM_ACTION_STATUS_NOTATHOME, GAIM_ACTION_STATUS_AWAY, TRUE, "notAtHome"}, + { GAIM_ACTION_STATUS_NOTATMYDESK, GAIM_ACTION_STATUS_AWAY, TRUE, "notAtMyDesk"}, + { GAIM_ACTION_STATUS_NOTAVAILABLE, GAIM_ACTION_STATUS_AWAY, TRUE, "notAvailable"}, + { GAIM_ACTION_STATUS_NOTINTHEOFFICE, GAIM_ACTION_STATUS_AWAY, TRUE, "notInTheOffice"}, + { GAIM_ACTION_STATUS_ONTHEPHONE, GAIM_ACTION_STATUS_AWAY, TRUE, "onThePhone"}, + { GAIM_ACTION_STATUS_ONVACATION, GAIM_ACTION_STATUS_AWAY, TRUE, "onVacation"}, + { GAIM_ACTION_STATUS_OUTTOLUNCH, GAIM_ACTION_STATUS_AWAY, TRUE, "outToLunch"}, + { GAIM_ACTION_STATUS_STEPPEDOUT, GAIM_ACTION_STATUS_AWAY, TRUE, "steppedOut"}, + { GAIM_ACTION_UNSET_EVENT, GAIM_ACTION_UNSET_EVENT, FALSE, NULL}, + { GAIM_ACTION_EVENT_LOGSTARTED, GAIM_ACTION_UNSET_ACTION, FALSE, "logStarted"}, + { GAIM_ACTION_EVENT_LOGENDED, GAIM_ACTION_UNSET_ACTION, FALSE, "logEnded"}, + { GAIM_ACTION_EVENT_WINDOWOPENED, GAIM_ACTION_UNSET_ACTION, FALSE, "windowOpened"}, + { GAIM_ACTION_EVENT_WINDOWCLOSED, GAIM_ACTION_UNSET_ACTION, FALSE, "windowClosed"}, + { GAIM_ACTION_EVENT_FILETRANSFERREQUESTED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferRequested"}, + { GAIM_ACTION_EVENT_FILETRANSFERREJECTED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferRejected"}, + { GAIM_ACTION_EVENT_FILETRANSFERACCEPTED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferAccepted"}, + { GAIM_ACTION_EVENT_FILETRANSFERSTARTED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferStarted"}, + { GAIM_ACTION_EVENT_FILETRANSFERABORTED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferAborted"}, + { GAIM_ACTION_EVENT_FILETRANSFERCOMPLETED, GAIM_ACTION_UNSET_ACTION, TRUE, "fileTransferCompleted"}, + { GAIM_ACTION_EVENT_AUTHORIZATIONREQUESTED, GAIM_ACTION_UNSET_ACTION, TRUE, "authorizationRequested"}, + { GAIM_ACTION_EVENT_AUTHORIZATIONDENIED, GAIM_ACTION_UNSET_ACTION, TRUE, "authorizationDenied"}, + { GAIM_ACTION_EVENT_AUTHORIZATIONCANCELLED, GAIM_ACTION_UNSET_ACTION, TRUE, "authorizationCancelled"}, + { GAIM_ACTION_EVENT_AUTHORZATIONGRANTED, GAIM_ACTION_UNSET_ACTION, TRUE, "authorizationGranted"}, + { GAIM_ACTION_EVENT_CHANNELMODES, GAIM_ACTION_UNSET_ACTION, TRUE, "channelModes"}, + { GAIM_ACTION_EVENT_CHANNELMODECHANGED, GAIM_ACTION_EVENT_CHANNELMODES, TRUE, "channelModeChanged"}, + { GAIM_ACTION_EVENT_CHANNELTOPIC, GAIM_ACTION_UNSET_ACTION, TRUE, "channelTopic"}, + { GAIM_ACTION_EVENT_CHANNELTOPICCHANGED, GAIM_ACTION_EVENT_CHANNELTOPIC, TRUE, "channelTopicChanged"}, + { GAIM_ACTION_EVENT_SUBJECT, GAIM_ACTION_UNSET_ACTION, TRUE, "subject"}, + { GAIM_ACTION_EVENT_SUBJECTCHANGED, GAIM_ACTION_EVENT_SUBJECT, TRUE, "subjectChanged"}, + { GAIM_ACTION_EVENT_USERFORMATTEDID, GAIM_ACTION_UNSET_ACTION, TRUE, "userFormattedId"}, + { GAIM_ACTION_EVENT_USERFORMATTEDIDCHANGED, GAIM_ACTION_EVENT_USERFORMATTEDID, TRUE, "userFormattedIdChanged"}, + { GAIM_ACTION_EVENT_USERALIAS, GAIM_ACTION_UNSET_ACTION, TRUE, "userAlias"}, + { GAIM_ACTION_EVENT_USERALIASCHANGED, GAIM_ACTION_EVENT_USERALIAS, TRUE, "userAliasChanged"}, + { GAIM_ACTION_EVENT_USERHANDLE, GAIM_ACTION_UNSET_ACTION, TRUE, "userHandle"}, + { GAIM_ACTION_EVENT_USERHANDLECHANGED, GAIM_ACTION_EVENT_USERHANDLE, TRUE, "userHandleChanged"}, + { GAIM_ACTION_EVENT_USERPERMISSIONS, GAIM_ACTION_UNSET_ACTION, TRUE, "userPermissions"}, + { GAIM_ACTION_EVENT_USERPERMISSIONS_PROMOTED, GAIM_ACTION_EVENT_USERPERMISSIONS, TRUE, "userPermissions/promoted"}, + { GAIM_ACTION_EVENT_USERPERMISSIONS_DEMOTED, GAIM_ACTION_EVENT_USERPERMISSIONS, TRUE, "userPermissions/demoted"}, + { GAIM_ACTION_EVENT_USERPERMISSIONS_VOICED, GAIM_ACTION_EVENT_USERPERMISSIONS, TRUE, "userPermissions/voiced"}, + { GAIM_ACTION_EVENT_USERPERMISSIONS_DEVOICED, GAIM_ACTION_EVENT_USERPERMISSIONS, TRUE, "userPermissions/devoiced"}, + { GAIM_ACTION_EVENT_USERJOINED, GAIM_ACTION_UNSET_ACTION, TRUE, "userJoined"}, + { GAIM_ACTION_EVENT_USERPARTED, GAIM_ACTION_UNSET_ACTION, TRUE, "userParted"}, + { GAIM_ACTION_EVENT_USERQUIT, GAIM_ACTION_UNSET_ACTION, TRUE, "userQuit"}, + { GAIM_ACTION_EVENT_USERKICKED, GAIM_ACTION_UNSET_ACTION, TRUE, "userKicked"}, + { GAIM_ACTION_EVENT_USERBANNED, GAIM_ACTION_UNSET_ACTION, TRUE, "userBanned"}, + { GAIM_ACTION_EVENT_USERKLINED, GAIM_ACTION_UNSET_ACTION, TRUE, "userKlined"}, + { GAIM_ACTION_EVENT_USERGLINED, GAIM_ACTION_UNSET_ACTION, TRUE, "userGlined"} +}; + /************************************************************************** * PUBLIC LOGGING FUNCTIONS *********************************************** **************************************************************************/ @@ -177,6 +244,34 @@ } +void gaim_log_write_action(GaimLog *log, GaimActionType action, + const char *from, time_t time, const char *data) +{ + struct _gaim_logsize_user *lu; + gsize written, total = 0; + gpointer ptrsize; + + g_return_if_fail(log); + g_return_if_fail(log->logger); + g_return_if_fail(log->logger->write_action); + + written = (log->logger->write_action)(log, action, from, time, data); + + lu = g_new(struct _gaim_logsize_user, 1); + + lu->name = g_strdup(gaim_normalize(log->account, log->name)); + lu->account = log->account; + + if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) { + total = GPOINTER_TO_INT(ptrsize); + total += written; + g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(total)); + } else { + g_free(lu->name); + g_free(lu); + } +} + char *gaim_log_read(GaimLog *log, GaimLogReadFlags *flags) { GaimLogReadFlags mflags; @@ -360,8 +455,10 @@ logger->list_syslog = va_arg(args, void *); if (functions >= 9) logger->get_log_sets = va_arg(args, void *); + if (functions >= 10) + logger->write_action = va_arg(args, void *); - if (functions > 9) + if (functions > 10) gaim_debug_info("log", "Dropping new functions for logger: %s (%s)\n", name, id); va_end(args); @@ -545,6 +642,52 @@ } /**************************************************************************** + * LOG ACTION SUBSYSTEM ***************************************************** + ****************************************************************************/ +GaimActionData* gaim_log_action_get_actiondata(GaimActionType action) { + int i = 0; + for (i = 0; i < sizeof(supported_actions); i++) { + if (supported_actions[i].action != action) { + continue; + } + else { + return &(supported_actions[i]); + } + } + return NULL; +} + +gboolean gaim_log_action_is_event(GaimActionType action) { + // for now, we know the boundaries of GaimActionType enum declaration + return action > GAIM_ACTION_UNSET_EVENT; +} + +gboolean gaim_log_action_is_status(GaimActionType action) { + // for now, we know the boundaries of GaimActionType enum declaration + return (action > GAIM_ACTION_UNSET_STATUS && action < GAIM_ACTION_UNSET_EVENT); +} + +gboolean gaim_log_action_requires_sender(GaimActionType action) { + GaimActionData *action_data = gaim_log_action_get_actiondata(action); + + if (action_data != NULL) { + return action_data->requires_sender; + } + + return FALSE; +} + +const char* gaim_log_action_ulf_value(GaimActionType action) { + GaimActionData *action_data = gaim_log_action_get_actiondata(action); + + if (action_data != NULL) { + return action_data->ulf_value; + } + + return NULL; +} + +/**************************************************************************** * LOG SUBSYSTEM ************************************************************ ****************************************************************************/ @@ -568,15 +711,17 @@ gaim_prefs_add_string("/core/logging/format", "txt"); - xml_logger = gaim_log_logger_new("xml", _("Unified Log Format (XML)"), 8, + xml_logger = gaim_log_logger_new("xml", _("Unified Log Format (XML)"), 10, NULL, - xml_logger_write, + xml_logger_write_message, xml_logger_finalize, xml_logger_list, xml_logger_read, gaim_log_common_sizer, xml_logger_total_size, - xml_logger_list_syslog); + xml_logger_list_syslog, + NULL, + xml_logger_write_action); gaim_log_logger_add(xml_logger); html_logger = gaim_log_logger_new("html", _("HTML"), 8, @@ -1016,39 +1161,23 @@ } */ -static gsize xml_logger_write(GaimLog *log, - GaimMessageFlags type, - const char *from, time_t time, const char *message) -{ - char *msg_fixed; - char *date = g_strdup(gaim_utf8_strftime("%Y-%m-%d %H:%M:%S%z", localtime(&time))); +/** Returns the amount of data written to the file, and -1 if the file is unwritable. + * If the file is unwritable, then the integrity of log->logger_data is not guaranteed. */ +static gsize xml_logger_write_create(GaimLog *log, time_t time) { + if (!log->logger_data) { + /* This log is new. We could use the loggers 'new' function, but + * creating a new file there would result in empty files in the case + * that you open a convo with someone, but don't say anything. + */ - GaimPlugin *plugin = gaim_find_prpl(gaim_account_get_protocol_id(log->account)); - GaimLogCommonLoggerData *data = log->logger_data; - gsize written = 0, written_buf = 0; - GString *writebuf; - GIOStatus iostat; - GError *gerror = NULL; - gboolean log_corrected_html = gaim_prefs_get_bool("/core/logging/log_corrected_html"); - - char *from_normed = g_strdup(gaim_normalize(log->account, from)); - char *from_attributes; - if (strncmp(from, from_normed, strlen(from)) == 0) { - // if from is already normalized; leave senderformatted out - from_attributes = g_strconcat(" sender=\"", from_normed, "\"", NULL); - } else { - // from is NOT normalized; specifying senderformatted - from_attributes = g_strconcat(" sender=\"", from_normed, "\" senderformatted=\"", from, "\"", NULL); - } - - writebuf = g_string_new(""); - - /* This log is new. We could use the loggers 'new' function, but - * creating a new file there would result in empty files in the case - * that you open a convo with someone, but don't say anything. - */ - if (!log->logger_data) { + GaimPlugin *plugin = gaim_find_prpl(gaim_account_get_protocol_id(log->account)); + GaimLogCommonLoggerData *data = log->logger_data; + GString *writebuf = g_string_new(""); + char *date = g_strdup(gaim_utf8_strftime("%Y-%m-%d %H:%M:%S%z", localtime(&time))); + gsize written = 0; const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); + GIOStatus iostat; + GError *gerror = NULL; char *account_normed = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account))); char *account_attributes; @@ -1067,8 +1196,11 @@ data = log->logger_data; // if file doesn't exist, die - if (!data->channel) return 0; + if (!data->channel) { + return -1; + } + // directly write the event to prevent calling xml_logger_write_event, which calls us back g_string_printf(writebuf, "%c%c%c" "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" @@ -1078,21 +1210,58 @@ account_attributes, log->type == GAIM_LOG_SYSTEM ? " gaim:logtype=\"system\"" : "", date); - iostat = g_io_channel_write_chars(data->channel, writebuf->str, -1, &written_buf, &gerror); + iostat = g_io_channel_write_chars(data->channel, writebuf->str, -1, &written, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not write to new file: %s\n", gerror->message); + gaim_debug_info("log", "xml_logger_write_common could not write to new file: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } - else written += written_buf; g_free(account_normed); g_free(account_attributes); + g_string_free(writebuf, TRUE); + return written; } + return 0; +} - /* if we can't write to the file, give up before we hurt ourselves */ - if(!data->channel) +static gsize xml_logger_write_message(GaimLog *log, + GaimMessageFlags type, + const char *from, time_t time, const char *message) +{ + char *date = g_strdup(gaim_utf8_strftime("%Y-%m-%d %H:%M:%S%z", localtime(&time))); + + GaimLogCommonLoggerData *data; + gsize written = 0, written_buf = 0; + GString *writebuf; + GIOStatus iostat; + GError *gerror = NULL; + + char *from_normed = g_strdup(gaim_normalize(log->account, from)); + char *from_attributes; /**< The XML string of attributes for sender and senderformatted. */ + + gboolean log_corrected_html = gaim_prefs_get_bool("/core/logging/log_corrected_html"); + char *msg_fixed; + + if (strncmp(from, from_normed, strlen(from)) == 0) { + // if from is already normalized; leave senderformatted out + from_attributes = g_strconcat(" sender=\"", from_normed, "\"", NULL); + } else { + // from is NOT normalized; specifying senderformatted + from_attributes = g_strconcat(" sender=\"", from_normed, "\" senderformatted=\"", from, "\"", NULL); + } + + writebuf = g_string_new(""); + + // create the logfile if it doesn't exist + written = xml_logger_write_create(log, time); + /* if we can't write to the file, give up before we hurt ourselves + * if xml_logger_write_common returns -1, the log file is not available */ + if (written == -1) { + gaim_debug_info("log", "xml_logger_write_message could not create the new logfile\n"); return 0; + } + data = log->logger_data; if (log_corrected_html) { gaim_markup_html_to_xhtml(message, &msg_fixed, NULL); @@ -1150,7 +1319,7 @@ iostat = g_io_channel_write_chars(data->channel, writebuf->str, -1, &written_buf, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not the message to the logfile: %s\n", gerror->message); + gaim_debug_info("log", "xml_logger_write_message could not the message to the logfile: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } @@ -1158,43 +1327,131 @@ g_free(date); if (log_corrected_html) { - // free only if we need to free this + // free only if we used this g_free(msg_fixed); } + xml_logger_append_footer(data->channel); + + g_free(from_normed); + g_free(from_attributes); + g_string_free(writebuf, TRUE); + return written; +} + +static gsize xml_logger_write_action(GaimLog *log, GaimActionType action, + const char *from, time_t time, const char *tagdata) { + char *date = g_strdup(gaim_utf8_strftime("%Y-%m-%d %H:%M:%S%z", localtime(&time))); + + GaimLogCommonLoggerData *data = log->logger_data; + GIOStatus iostat; + GError *gerror = NULL; + + gsize written = 0; + GString *writebuf = g_string_new(""); + + char *from_attributes; + if (from) { + char *from_normed = g_strdup(gaim_normalize(log->account, from)); + + if (strncmp(from, from_normed, strlen(from)) == 0) { + // if from is already normalized; leave senderformatted out + from_attributes = g_strconcat(" sender=\"", from_normed, "\"", NULL); + } else { + // from is NOT normalized; specifying senderformatted + from_attributes = g_strconcat(" sender=\"", from_normed, "\" senderformatted=\"", from, "\"", NULL); + } + + g_free(from_normed); + } + else { + // there is no sender attribute for this action + from_attributes = g_strconcat("", NULL); + + if (gaim_log_action_requires_sender(action)) { + gaim_debug_error("log", "xml_logger_write_action is writing an action that does not have the required sender attribute\n"); + } + } + + // create the log file if it doesn't exist, and die if it fails + written = xml_logger_write_create(log, time); + if (written == -1) { + gaim_debug_info("log", "xml_logger_write_action could not create the new logfile\n"); + return 0; + } + + // create the log action + if (tagdata != NULL && strlen(tagdata) > 0) { + g_string_printf(writebuf, "\t<event time=\"%s\"%s type=\"%s\">%s</event>\n", date, from_attributes, + gaim_log_action_ulf_value(action), tagdata); + } + else { + g_string_printf(writebuf, "\t<event time=\"%s\"%s type=\"%s\" />\n", date, from_attributes, + gaim_log_action_ulf_value(action)); + } + + // write it + iostat = g_io_channel_write_chars(data->channel, writebuf->str, -1, &written, &gerror); + if (iostat == G_IO_STATUS_ERROR) { + gaim_debug_info("log", "xml_logger_write_action could not write the action to the log file: %s\n", gerror->message); + g_error_free(gerror); + gerror = NULL; + } + + xml_logger_append_footer(data->channel); + + g_free(date); + g_free(from_attributes); + g_string_free(writebuf, TRUE); + + return written; +} + +static gboolean xml_logger_append_footer(GIOChannel *channel) { + GIOStatus iostat; + GString *writebuf; + GError *gerror = NULL; + gsize written_buf = 0; + + if (!channel) { + return FALSE; + } + + writebuf = g_string_new(""); + // append suffix to file and seek back to keep a valid XML document out of the user space buffer g_string_printf(writebuf, "\t<event time=\"%s\" type=\"logEnd\" />\n" "</chat>\n", gaim_utf8_strftime("%Y-%m-%d %H:%M:%S%z", NULL)); - iostat = g_io_channel_write_chars(data->channel, writebuf->str, -1, &written_buf, &gerror); + iostat = g_io_channel_write_chars(channel, writebuf->str, -1, &written_buf, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not write the tail to the logfile: %s\n", gerror->message); + gaim_debug_info("log", "xml_logger_write_message could not write the tail to the logfile: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } - iostat = g_io_channel_seek_position(data->channel, -1*(gint64)(written_buf), G_SEEK_CUR, &gerror); + iostat = g_io_channel_seek_position(channel, -1*(gint64)(written_buf), G_SEEK_CUR, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not seek backwards to the beginning of the tail: %s\n", gerror->message); + gaim_debug_info("log", "xml_logger_write_message could not seek backwards to the beginning of the tail: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } - iostat = g_io_channel_flush(data->channel, &gerror); + iostat = g_io_channel_flush(channel, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not flush the logfile: %s\n", gerror->message); + gaim_debug_info("log", "xml_logger_write_message could not flush the logfile: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } - g_free(from_normed); - g_free(from_attributes); g_string_free(writebuf, TRUE); - return written; + + return TRUE; } + static void xml_logger_finalize(GaimLog *log) { GaimLogCommonLoggerData *data = log->logger_data; @@ -1399,7 +1656,7 @@ iostat = g_io_channel_flush(data->channel, &gerror); if (iostat == G_IO_STATUS_ERROR) { - gaim_debug_info("log", "xml_logger_write could not flush the logfile: %s\n", gerror->message); + gaim_debug_info("log", "html_logger_write could not flush the logfile: %s\n", gerror->message); g_error_free(gerror); gerror = NULL; } Modified: branches/soc-2006-file-loggers/src/log.h =================================================================== --- branches/soc-2006-file-loggers/src/log.h 2006-08-09 03:41:45 UTC (rev 16674) +++ branches/soc-2006-file-loggers/src/log.h 2006-08-09 04:21:36 UTC (rev 16675) @@ -36,6 +36,7 @@ typedef struct _GaimLogLogger GaimLogLogger; typedef struct _GaimLogCommonLoggerData GaimLogCommonLoggerData; typedef struct _GaimLogSet GaimLogSet; +typedef struct _GaimActionData GaimActionData; typedef enum { GAIM_LOG_IM, @@ -48,51 +49,72 @@ } GaimLogReadFlags; /** - * A list of recognizable events that are logged. + * A list of recognizable actions that are logged. */ typedef enum { - GAIM_EVENT_UNSET = 0, - GAIM_EVENT_LOGSTARTED, - GAIM_EVENT_LOGENDED, - GAIM_EVENT_WINDOWOPENED, - GAIM_EVENT_WINDOWCLOSED, - GAIM_EVENT_FILETRANSFERREQUESTED, - GAIM_EVENT_FILETRANSFERREJECTED, - GAIM_EVENT_FILETRANSFERACCEPTED, - GAIM_EVENT_FILETRANSFERSTARTED, - GAIM_EVENT_FILETRANSFERABORTED, - GAIM_EVENT_FILETRANSFERCOMPLETED, - GAIM_EVENT_AUTHORIZATIONREQUESTED, - GAIM_EVENT_AUTHORIZATIONDENIED, - GAIM_EVENT_AUTHORIZATIONCANCELLED, - GAIM_EVENT_AUTHORZATIONGRANTED, - GAIM_EVENT_CHANNELMODES, - GAIM_EVENT_CHANNELMODECHANGED, - GAIM_EVENT_CHANNELTOPIC, - GAIM_EVENT_CHANNELTOPICCHANGED, - GAIM_EVENT_SUBJECT, - GAIM_EVENT_SUBJECTCHANGED, - GAIM_EVENT_USERFORMATTEDID, - GAIM_EVENT_USERFORMATTEDIDCHANGED, - GAIM_EVENT_USERALIAS, - GAIM_EVENT_USERALIASCHANGED, - GAIM_EVENT_USERHANDLE, - GAIM_EVENT_USERHANDLECHANGED, - GAIM_EVENT_USERPERMISSIONS, - GAIM_EVENT_USERPERMISSIONS_PROMOTED, - GAIM_EVENT_USERPERMISSIONS_DEMOTED, - GAIM_EVENT_USERPERMISSIONS_VOICED, - GAIM_EVENT_USERPERMISSIONS_DEVOICED, - GAIM_EVENT_USERJOINED, - GAIM_EVENT_USERPARTED, - GAIM_EVENT_USERQUIT, - GAIM_EVENT_USERKICKED, - GAIM_EVENT_USERBANNED, - GAIM_EVENT_USERKLINED, - GAIM_EVENT_USERGLINED, - GAIM_TOTAL_EVENTS -} GaimEvents; + GAIM_ACTION_UNSET_ACTION = 0, + GAIM_ACTION_UNSET_STATUS, /**< Placeholder/Boundary of the first STATUS action types. */ + GAIM_ACTION_STATUS_ONLINE, + GAIM_ACTION_STATUS_FREETOCHAT, + GAIM_ACTION_STATUS_MOBILE, + GAIM_ACTION_STATUS_OFFLINE, + GAIM_ACTION_STATUS_INVISIBLE, + GAIM_ACTION_STATUS_AWAY, + GAIM_ACTION_STATUS_BERIGHTBACK, + GAIM_ACTION_STATUS_BUSY, + GAIM_ACTION_STATUS_DONOTDISTURB, + GAIM_ACTION_STATUS_EXTENDEDAWAY, + GAIM_ACTION_STATUS_GONEHOME, + GAIM_ACTION_STATUS_INAMEETING, + GAIM_ACTION_STATUS_NOTATHOME, + GAIM_ACTION_STATUS_NOTATMYDESK, + GAIM_ACTION_STATUS_NOTAVAILABLE, + GAIM_ACTION_STATUS_NOTINTHEOFFICE, + GAIM_ACTION_STATUS_ONTHEPHONE, + GAIM_ACTION_STATUS_ONVACATION, + GAIM_ACTION_STATUS_OUTTOLUNCH, + GAIM_ACTION_STATUS_STEPPEDOUT, + GAIM_ACTION_UNSET_EVENT, /**< Placeholder/Boundary of the first EVENT action types. */ + GAIM_ACTION_EVENT_LOGSTARTED, + GAIM_ACTION_EVENT_LOGENDED, + GAIM_ACTION_EVENT_WINDOWOPENED, + GAIM_ACTION_EVENT_WINDOWCLOSED, + GAIM_ACTION_EVENT_FILETRANSFERREQUESTED, + GAIM_ACTION_EVENT_FILETRANSFERREJECTED, + GAIM_ACTION_EVENT_FILETRANSFERACCEPTED, + GAIM_ACTION_EVENT_FILETRANSFERSTARTED, + GAIM_ACTION_EVENT_FILETRANSFERABORTED, + GAIM_ACTION_EVENT_FILETRANSFERCOMPLETED, + GAIM_ACTION_EVENT_AUTHORIZATIONREQUESTED, + GAIM_ACTION_EVENT_AUTHORIZATIONDENIED, + GAIM_ACTION_EVENT_AUTHORIZATIONCANCELLED, + GAIM_ACTION_EVENT_AUTHORZATIONGRANTED, + GAIM_ACTION_EVENT_CHANNELMODES, + GAIM_ACTION_EVENT_CHANNELMODECHANGED, + GAIM_ACTION_EVENT_CHANNELTOPIC, + GAIM_ACTION_EVENT_CHANNELTOPICCHANGED, + GAIM_ACTION_EVENT_SUBJECT, + GAIM_ACTION_EVENT_SUBJECTCHANGED, + GAIM_ACTION_EVENT_USERFORMATTEDID, + GAIM_ACTION_EVENT_USERFORMATTEDIDCHANGED, + GAIM_ACTION_EVENT_USERALIAS, + GAIM_ACTION_EVENT_USERALIASCHANGED, + GAIM_ACTION_EVENT_USERHANDLE, + GAIM_ACTION_EVENT_USERHANDLECHANGED, + GAIM_ACTION_EVENT_USERPERMISSIONS, + GAIM_ACTION_EVENT_USERPERMISSIONS_PROMOTED, + GAIM_ACTION_EVENT_USERPERMISSIONS_DEMOTED, + GAIM_ACTION_EVENT_USERPERMISSIONS_VOICED, + GAIM_ACTION_EVENT_USERPERMISSIONS_DEVOICED, + GAIM_ACTION_EVENT_USERJOINED, + GAIM_ACTION_EVENT_USERPARTED, + GAIM_ACTION_EVENT_USERQUIT, + GAIM_ACTION_EVENT_USERKICKED, + GAIM_ACTION_EVENT_USERBANNED, + GAIM_ACTION_EVENT_USERKLINED, + GAIM_ACTION_EVENT_USERGLINED +} GaimActionType; #include "account.h" #include "conversation.h" @@ -113,29 +135,29 @@ I don't think this is actually needed. */ void (*create)(GaimLog *log); - /** This is used to write to the log file */ + /** This is used to write a message to the log file. */ gsize (*write)(GaimLog *log, GaimMessageFlags type, const char *from, time_t time, const char *message); - /** Called when the log is destroyed */ + /** Called when the log is destroyed. */ void (*finalize)(GaimLog *log); - /** This function returns a sorted GList of available GaimLogs */ + /** This function returns a sorted GList of available GaimLogs. */ GList *(*list)(GaimLogType type, const char *name, GaimAccount *account); /** Given one of the logs returned by the logger's list function, - * this returns the contents of the log in GtkIMHtml markup */ + * this returns the contents of the log in GtkIMHtml markup. */ char *(*read)(GaimLog *log, GaimLogReadFlags *flags); /** Given one of the logs returned by the logger's list function, - * this returns the size of the log in bytes */ + * this returns the size of the log in bytes. */ int (*size)(GaimLog *log); /** Returns the total size of all the logs. If this is undefined a default - * implementation is used */ + * implementation is used. */ int (*total_size)(GaimLogType type, const char *name, GaimAccount *account); /** This function returns a sorted GList of available system GaimLogs */ @@ -150,6 +172,13 @@ * Loggers which implement this function must create a GaimLogSet, * then call @a cb with @a sets and the newly created GaimLogSet. */ void (*get_log_sets)(GaimLogSetCallback cb, GHashTable *sets); + + /** This is used to write an action (event or status) to the log file. */ + gsize (*write_action)(GaimLog *log, + GaimActionType action, + const char *from, + time_t time, + const char *tagdata); }; /** @@ -215,6 +244,18 @@ * IMPORTANT: Update that code if you add members here. */ }; +/** + * Describes a specific action type and its attributes. + */ +struct _GaimActionData { + GaimActionType action; /**< The action, which is an action or status. **/ + GaimActionType parent_action; /**< The parent action, if there is one. + * If not, this will be set to NULL or GAIM_ACTION_UNSET. */ + gboolean requires_sender; /**< Indicates whether a sender is required, + * or if the action must have an origin. */ + const char *ulf_value; /**< The corresponding ULF formatted attribute value. */ +}; + #ifdef __cplusplus extern "C" { #endif @@ -248,7 +289,7 @@ void gaim_log_free(GaimLog *log); /** - * Writes to a log file. Assumes you have checked preferences already. + * Writes messages to a log file. Assumes you have checked preferences already. * * @param log The log to write to * @param type The type of message being logged @@ -264,6 +305,22 @@ const char *message); /** + * Writes actions to a log file. Assumes you have checked preferences already. + * + * @param log The log to write to + * @param action The action that occured + * @param from For whom this acton occured, or @c NULL + * if action does not have an origin + * @param time A timestamp in UNIX time + * @param tagdata Any action-associated data to be saved in the action element + */ +void gaim_log_write_action(GaimLog *log, + GaimActionType action, + const char *from, + time_t time, + const char *tagdata); + +/** * Reads from a log * * @param log The log to read from @@ -505,6 +562,57 @@ GList *gaim_log_logger_get_options(void); /**************************************************************************/ +/** @name Action Utilities for Logging functions */ +/**************************************************************************/ +/*@{*/ + +/** + * Returns the corresponding GaimActionData struct of a GaimAction. + * + * @param action The action + * + * @return GaimActionData struct + */ +GaimActionData* gaim_log_action_get_actiondata(GaimActionType action); + +/** + * Returns true if the GaimActionType action is an event + * + * @param action The action + * + * @return True if action is an event + */ +gboolean gaim_log_action_is_event(GaimActionType action); + +/** + * Returns true if the GaimActionType action is an status + * + * @param action The action + * + * @return True if action is a status + */ +gboolean gaim_log_action_is_status(GaimActionType action); + +/** + * Returns true if the GaimAction requires a sender or a from. + * + * @param action The action + * + * @return True if <code>event</code> or <code>status</code> element requires a sender. + */ +gboolean gaim_log_action_requires_sender(GaimActionType action); + +/** + * Returns the corresponding ULF attribute value of an action. + * + * @param action The action + * + * @return The corresponding ULF attribute value + */ +const char* gaim_log_action_ulf_value(GaimActionType action); + +/*@}*/ +/**************************************************************************/ /** @name Log Subsystem */ /**************************************************************************/ /*@{*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |